diff --git a/.env b/.env
index 55f47e18df..00d48ed6a2 100644
--- a/.env
+++ b/.env
@@ -10,13 +10,16 @@ NEXT_PUBLIC_API_BASE_URL=${API_BASE_URL}
NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs
AUTH_TRUST_HOST=true
UI_PORT=3000
-# Temp URL for feeds need to use actual
-RSS_FEED_URL=https://prowler.com/blog/rss
# openssl rand -base64 32
AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8="
# Google Tag Manager ID
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=""
+#### Code Review Configuration ####
+# Enable Claude Code standards validation on pre-push hook
+# Set to 'true' to validate changes against AGENTS.md standards via Claude Code
+# Set to 'false' to skip validation
+CODE_REVIEW_ENABLED=true
#### Prowler API Configuration ####
PROWLER_API_VERSION="stable"
@@ -29,6 +32,14 @@ POSTGRES_ADMIN_PASSWORD=postgres
POSTGRES_USER=prowler
POSTGRES_PASSWORD=postgres
POSTGRES_DB=prowler_db
+# Read replica settings (optional)
+# POSTGRES_REPLICA_HOST=postgres-db
+# POSTGRES_REPLICA_PORT=5432
+# POSTGRES_REPLICA_USER=prowler
+# POSTGRES_REPLICA_PASSWORD=postgres
+# POSTGRES_REPLICA_DB=prowler_db
+# POSTGRES_REPLICA_MAX_ATTEMPTS=3
+# POSTGRES_REPLICA_RETRY_BASE_DELAY=0.5
# Celery-Prowler task settings
TASK_RETRY_DELAY_SECONDS=0.1
@@ -85,55 +96,23 @@ DJANGO_CACHE_MAX_AGE=3600
DJANGO_STALE_WHILE_REVALIDATE=60
DJANGO_MANAGE_DB_PARTITIONS=True
# openssl genrsa -out private.pem 2048
-DJANGO_TOKEN_SIGNING_KEY="-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDs4e+kt7SnUJek
-6V5r9zMGzXCoU5qnChfPiqu+BgANyawz+MyVZPs6RCRfeo6tlCknPQtOziyXYM2I
-7X+qckmuzsjqp8+u+o1mw3VvUuJew5k2SQLPYwsiTzuFNVJEOgRo3hywGiGwS2iv
-/5nh2QAl7fq2qLqZEXQa5+/xJlQggS1CYxOJgggvLyra50QZlBvPve/AxKJ/EV/Q
-irWTZU5lLNI8sH2iZR05vQeBsxZ0dCnGMT+vGl+cGkqrvzQzKsYbDmabMcfTYhYi
-78fpv6A4uharJFHayypYBjE39PwhMyyeycrNXlpm1jpq+03HgmDuDMHydk1tNwuT
-nEC7m7iNAgMBAAECggEAA2m48nJcJbn9SVi8bclMwKkWmbJErOnyEGEy2sTK3Of+
-NWx9BB0FmqAPNxn0ss8K7cANKOhDD7ZLF9E2MO4/HgfoMKtUzHRbM7MWvtEepldi
-nnvcUMEgULD8Dk4HnqiIVjt3BdmGiTv46OpBnRWrkSBV56pUL+7msZmMZTjUZvh2
-ZWv0+I3gtDIjo2Zo/FiwDV7CfwRjJarRpYUj/0YyuSA4FuOUYl41WAX1I301FKMH
-xo3jiAYi1s7IneJ16OtPpOA34Wg5F6ebm/UO0uNe+iD4kCXKaZmxYQPh5tfB0Qa3
-qj1T7GNpFNyvtG7VVdauhkb8iu8X/wl6PCwbg0RCKQKBgQD9HfpnpH0lDlHMRw9K
-X7Vby/1fSYy1BQtlXFEIPTN/btJ/asGxLmAVwJ2HAPXWlrfSjVAH7CtVmzN7v8oj
-HeIHfeSgoWEu1syvnv2AMaYSo03UjFFlfc/GUxF7DUScRIhcJUPCP8jkAROz9nFv
-DByNjUL17Q9r43DmDiRsy0IFqQKBgQDvlJ9Uhl+Sp7gRgKYwa/IG0+I4AduAM+Gz
-Dxbm52QrMGMTjaJFLmLHBUZ/ot+pge7tZZGws8YR8ufpyMJbMqPjxhIvRRa/p1Tf
-E3TQPW93FMsHUvxAgY3MV5MzXFPhlNAKb+akP/RcXUhetGAuZKLubtDCWa55ZQuL
-wj2OS+niRQKBgE7K8zUqNi6/22S8xhy/2GPgB1qPObbsABUofK0U6CAGLo6te+gc
-6Jo84IyzFtQbDNQFW2Fr+j1m18rw9AqkdcUhQndiZS9AfG07D+zFB86LeWHt4DS4
-ymIRX8Kvaak/iDcu/n3Mf0vCrhB6aetImObTj4GgrwlFvtJOmrYnO8EpAoGAIXXP
-Xt25gWD9OyyNiVu6HKwA/zN7NYeJcRmdaDhO7B1A6R0x2Zml4AfjlbXoqOLlvLAf
-zd79vcoAC82nH1eOPiSOq51plPDI0LMF8IN0CtyTkn1Lj7LIXA6rF1RAvtOqzppc
-SvpHpZK9pcRpXnFdtBE0BMDDtl6fYzCIqlP94UUCgYEAnhXbAQMF7LQifEm34Dx8
-BizRMOKcqJGPvbO2+Iyt50O5X6onU2ITzSV1QHtOvAazu+B1aG9pEuBFDQ+ASxEu
-L9ruJElkOkb/o45TSF6KCsHd55ReTZ8AqnRjf5R+lyzPqTZCXXb8KTcRvWT4zQa3
-VxyT2PnaSqEcexWUy4+UXoQ=
------END PRIVATE KEY-----"
+DJANGO_TOKEN_SIGNING_KEY=""
# openssl rsa -in private.pem -pubout -out public.pem
-DJANGO_TOKEN_VERIFYING_KEY="-----BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7OHvpLe0p1CXpOlea/cz
-Bs1wqFOapwoXz4qrvgYADcmsM/jMlWT7OkQkX3qOrZQpJz0LTs4sl2DNiO1/qnJJ
-rs7I6qfPrvqNZsN1b1LiXsOZNkkCz2MLIk87hTVSRDoEaN4csBohsEtor/+Z4dkA
-Je36tqi6mRF0Gufv8SZUIIEtQmMTiYIILy8q2udEGZQbz73vwMSifxFf0Iq1k2VO
-ZSzSPLB9omUdOb0HgbMWdHQpxjE/rxpfnBpKq780MyrGGw5mmzHH02IWIu/H6b+g
-OLoWqyRR2ssqWAYxN/T8ITMsnsnKzV5aZtY6avtNx4Jg7gzB8nZNbTcLk5xAu5u4
-jQIDAQAB
------END PUBLIC KEY-----"
+DJANGO_TOKEN_VERIFYING_KEY=""
# openssl rand -base64 32
DJANGO_SECRETS_ENCRYPTION_KEY="oE/ltOhp/n1TdbHjVmzcjDPLcLA41CVI/4Rk+UB5ESc="
DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
DJANGO_SENTRY_DSN=
+DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
# Sentry settings
SENTRY_ENVIRONMENT=local
SENTRY_RELEASE=local
+NEXT_PUBLIC_SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
+
#### Prowler release version ####
-NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.10.0
+NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.12.2
# Social login credentials
SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google"
@@ -152,3 +131,12 @@ LANGSMITH_TRACING=false
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY=""
LANGCHAIN_PROJECT=""
+
+# RSS Feed Configuration
+# Multiple feed sources can be configured as a JSON array (must be valid JSON, no trailing commas)
+# Each source requires: id, name, type (github_releases|blog|custom), url, and enabled flag
+# IMPORTANT: Must be a single line with valid JSON (no newlines, no trailing commas)
+# Example with one source:
+RSS_FEED_SOURCES='[{"id":"prowler-releases","name":"Prowler Releases","type":"github_releases","url":"https://github.com/prowler-cloud/prowler/releases.atom","enabled":true}]'
+# Example with multiple sources (no trailing comma after last item):
+# RSS_FEED_SOURCES='[{"id":"prowler-releases","name":"Prowler Releases","type":"github_releases","url":"https://github.com/prowler-cloud/prowler/releases.atom","enabled":true},{"id":"prowler-blog","name":"Prowler Blog","type":"blog","url":"https://prowler.com/blog/rss","enabled":false}]'
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 74e9332e34..b953610fa1 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,6 +1,28 @@
+# SDK
/* @prowler-cloud/sdk
-/.github/ @prowler-cloud/sdk
-prowler @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
-tests @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
-api @prowler-cloud/api
-ui @prowler-cloud/ui
\ No newline at end of file
+/prowler/ @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
+/tests/ @prowler-cloud/sdk @prowler-cloud/detection-and-remediation
+/dashboard/ @prowler-cloud/sdk
+/docs/ @prowler-cloud/sdk
+/examples/ @prowler-cloud/sdk
+/util/ @prowler-cloud/sdk
+/contrib/ @prowler-cloud/sdk
+/permissions/ @prowler-cloud/sdk
+/codecov.yml @prowler-cloud/sdk @prowler-cloud/api
+
+# API
+/api/ @prowler-cloud/api
+
+# UI
+/ui/ @prowler-cloud/ui
+
+# AI
+/mcp_server/ @prowler-cloud/ai
+
+# Platform
+/.github/ @prowler-cloud/platform
+/Makefile @prowler-cloud/platform
+/kubernetes/ @prowler-cloud/platform
+**/Dockerfile* @prowler-cloud/platform
+**/docker-compose*.yml @prowler-cloud/platform
+**/docker-compose*.yaml @prowler-cloud/platform
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index fa4c805d85..fcba29ca1f 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -3,6 +3,41 @@ description: Create a report to help us improve
labels: ["bug", "status/needs-triage"]
body:
+ - type: checkboxes
+ id: search
+ attributes:
+ label: Issue search
+ options:
+ - label: I have searched the existing issues and this bug has not been reported yet
+ required: true
+ - type: dropdown
+ id: component
+ attributes:
+ label: Which component is affected?
+ multiple: true
+ options:
+ - Prowler CLI/SDK
+ - Prowler API
+ - Prowler UI
+ - Prowler Dashboard
+ - Prowler MCP Server
+ - Documentation
+ - Other
+ validations:
+ required: true
+ - type: dropdown
+ id: provider
+ attributes:
+ label: Cloud Provider (if applicable)
+ multiple: true
+ options:
+ - AWS
+ - Azure
+ - GCP
+ - Kubernetes
+ - GitHub
+ - Microsoft 365
+ - Not applicable
- type: textarea
id: reproduce
attributes:
@@ -78,6 +113,15 @@ body:
prowler --version
validations:
required: true
+ - type: input
+ id: python-version
+ attributes:
+ label: Python version
+ description: Which Python version are you using?
+ placeholder: |-
+ python --version
+ validations:
+ required: true
- type: input
id: pip-version
attributes:
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 3ba13e0cec..6e7c21013b 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1 +1,11 @@
blank_issues_enabled: false
+contact_links:
+ - name: š Documentation
+ url: https://docs.prowler.com
+ about: Check our comprehensive documentation for guides and tutorials
+ - name: š¬ GitHub Discussions
+ url: https://github.com/prowler-cloud/prowler/discussions
+ about: Ask questions and discuss with the community
+ - name: š Prowler Community
+ url: https://goto.prowler.com/slack
+ about: Join our community for support and updates
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml
index 528723b717..3e3510496f 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.yml
+++ b/.github/ISSUE_TEMPLATE/feature-request.yml
@@ -3,6 +3,42 @@ description: Suggest an idea for this project
labels: ["feature-request", "status/needs-triage"]
body:
+ - type: checkboxes
+ id: search
+ attributes:
+ label: Feature search
+ options:
+ - label: I have searched the existing issues and this feature has not been requested yet or is already in our [Public Roadmap](https://roadmap.prowler.com/roadmap)
+ required: true
+ - type: dropdown
+ id: component
+ attributes:
+ label: Which component would this feature affect?
+ multiple: true
+ options:
+ - Prowler CLI/SDK
+ - Prowler API
+ - Prowler UI
+ - Prowler Dashboard
+ - Prowler MCP Server
+ - Documentation
+ - New component/Integration
+ validations:
+ required: true
+ - type: dropdown
+ id: provider
+ attributes:
+ label: Related to specific cloud provider?
+ multiple: true
+ options:
+ - AWS
+ - Azure
+ - GCP
+ - Kubernetes
+ - GitHub
+ - Microsoft 365
+ - All providers
+ - Not provider-specific
- type: textarea
id: Problem
attributes:
@@ -19,6 +55,14 @@ body:
description: A clear and concise description of what you want to happen.
validations:
required: true
+ - type: textarea
+ id: use-case
+ attributes:
+ label: Use case and benefits
+ description: Who would benefit from this feature and how?
+ placeholder: This would help security teams by...
+ validations:
+ required: true
- type: textarea
id: Alternatives
attributes:
diff --git a/.github/actions/setup-python-poetry/action.yml b/.github/actions/setup-python-poetry/action.yml
new file mode 100644
index 0000000000..790f3ef0e6
--- /dev/null
+++ b/.github/actions/setup-python-poetry/action.yml
@@ -0,0 +1,93 @@
+name: 'Setup Python with Poetry'
+description: 'Setup Python environment with Poetry and install dependencies'
+author: 'Prowler'
+
+inputs:
+ python-version:
+ description: 'Python version to use'
+ required: true
+ working-directory:
+ description: 'Working directory for Poetry'
+ required: false
+ default: '.'
+ poetry-version:
+ description: 'Poetry version to install'
+ required: false
+ default: '2.1.1'
+ install-dependencies:
+ description: 'Install Python dependencies with Poetry'
+ required: false
+ default: 'true'
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Replace @master with current branch in pyproject.toml (prowler repo only)
+ if: github.event_name == 'pull_request' && github.base_ref == 'master' && github.repository == 'prowler-cloud/prowler'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ BRANCH_NAME="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}"
+ echo "Using branch: $BRANCH_NAME"
+ sed -i "s|@master|@$BRANCH_NAME|g" pyproject.toml
+
+ - name: Install poetry
+ shell: bash
+ run: |
+ python -m pip install --upgrade pip
+ pipx install poetry==${{ inputs.poetry-version }}
+
+ - name: Update poetry.lock with latest Prowler commit
+ if: github.repository_owner == 'prowler-cloud' && github.repository != 'prowler-cloud/prowler'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ LATEST_COMMIT=$(curl -s "https://api.github.com/repos/prowler-cloud/prowler/commits/master" | jq -r '.sha')
+ echo "Latest commit hash: $LATEST_COMMIT"
+ sed -i '/url = "https:\/\/github\.com\/prowler-cloud\/prowler\.git"/,/resolved_reference = / {
+ s/resolved_reference = "[a-f0-9]\{40\}"/resolved_reference = "'"$LATEST_COMMIT"'"/
+ }' poetry.lock
+ echo "Updated resolved_reference:"
+ grep -A2 -B2 "resolved_reference" poetry.lock
+
+ - name: Update SDK resolved_reference to latest commit (prowler repo on push)
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'prowler-cloud/prowler'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ LATEST_COMMIT=$(curl -s "https://api.github.com/repos/prowler-cloud/prowler/commits/master" | jq -r '.sha')
+ echo "Latest commit hash: $LATEST_COMMIT"
+ sed -i '/url = "https:\/\/github\.com\/prowler-cloud\/prowler\.git"/,/resolved_reference = / {
+ s/resolved_reference = "[a-f0-9]\{40\}"/resolved_reference = "'"$LATEST_COMMIT"'"/
+ }' poetry.lock
+ echo "Updated resolved_reference:"
+ grep -A2 -B2 "resolved_reference" poetry.lock
+
+ - name: Update poetry.lock (prowler repo only)
+ if: github.repository == 'prowler-cloud/prowler'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: poetry lock
+
+ - name: Set up Python ${{ inputs.python-version }}
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ inputs.python-version }}
+ cache: 'poetry'
+ cache-dependency-path: ${{ inputs.working-directory }}/poetry.lock
+
+ - name: Install Python dependencies
+ if: inputs.install-dependencies == 'true'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ poetry install --no-root
+ poetry run pip list
+
+ - name: Update Prowler Cloud API Client
+ if: github.repository_owner == 'prowler-cloud' && github.repository != 'prowler-cloud/prowler'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ poetry remove prowler-cloud-api-client
+ poetry add ./prowler-cloud-api-client
diff --git a/.github/actions/slack-notification/README.md b/.github/actions/slack-notification/README.md
new file mode 100644
index 0000000000..ce8843df2a
--- /dev/null
+++ b/.github/actions/slack-notification/README.md
@@ -0,0 +1,198 @@
+# Slack Notification Action
+
+A generic and flexible GitHub composite action for sending Slack notifications using JSON template files. Supports both standalone messages and message updates, with automatic status detection.
+
+## Features
+
+- **Template-based**: All messages use JSON template files for consistency
+- **Automatic status detection**: Pass `step-outcome` to auto-calculate success/failure
+- **Message updates**: Supports updating existing messages (using `chat.update`)
+- **Simple API**: Clean and minimal interface
+- **Reusable**: Use across all workflows and scenarios
+- **Maintainable**: Centralized message templates
+
+## Use Cases
+
+1. **Container releases**: Track push start and completion with automatic status
+2. **Deployments**: Track deployment progress with rich Block Kit formatting
+3. **Custom notifications**: Any scenario where you need to notify Slack
+
+## Inputs
+
+| Input | Description | Required | Default |
+|-------|-------------|----------|---------|
+| `slack-bot-token` | Slack bot token for authentication | Yes | - |
+| `payload-file-path` | Path to JSON file with the Slack message payload | Yes | - |
+| `update-ts` | Message timestamp to update (leave empty for new messages) | No | `''` |
+| `step-outcome` | Step outcome for automatic status detection (sets STATUS_EMOJI and STATUS_TEXT env vars) | No | `''` |
+
+## Outputs
+
+| Output | Description |
+|--------|-------------|
+| `ts` | Timestamp of the Slack message (use for updates) |
+
+## Usage Examples
+
+### Example 1: Container Release with Automatic Status Detection
+
+Using JSON template files with automatic status detection:
+
+```yaml
+# Send start notification
+- name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+# Do the work
+- name: Build and push container
+ if: github.event_name == 'release'
+ id: container-push
+ uses: docker/build-push-action@...
+ with:
+ push: true
+ tags: ...
+
+# Send completion notification with automatic status detection
+- name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+ step-outcome: ${{ steps.container-push.outcome }}
+```
+
+**Benefits:**
+- No status calculation needed in workflow
+- Reusable template files
+- Clean and concise
+- Automatic `STATUS_EMOJI` and `STATUS_TEXT` env vars set by action
+- Consistent message format across all workflows
+
+### Example 2: Deployment with Message Update Pattern
+
+```yaml
+# Send initial deployment message
+- name: Notify deployment started
+ id: slack-start
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ ENVIRONMENT: PRODUCTION
+ COMMIT_HASH: ${{ github.sha }}
+ VERSION_DEPLOYED: latest
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_WORKFLOW: ${{ github.workflow }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/deployment-started.json"
+
+# Run deployment
+- name: Deploy
+ id: deploy
+ run: terraform apply -auto-approve
+
+# Determine additional status variables
+- name: Determine deployment status
+ if: always()
+ id: deploy-status
+ run: |
+ if [[ "${{ steps.deploy.outcome }}" == "success" ]]; then
+ echo "STATUS_COLOR=28a745" >> $GITHUB_ENV
+ echo "STATUS=Completed" >> $GITHUB_ENV
+ else
+ echo "STATUS_COLOR=fc3434" >> $GITHUB_ENV
+ echo "STATUS=Failed" >> $GITHUB_ENV
+ fi
+
+# Update the same message with final status
+- name: Update deployment notification
+ if: always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ MESSAGE_TS: ${{ steps.slack-start.outputs.ts }}
+ COMPONENT: API
+ ENVIRONMENT: PRODUCTION
+ COMMIT_HASH: ${{ github.sha }}
+ VERSION_DEPLOYED: latest
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_WORKFLOW: ${{ github.workflow }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ STATUS: ${{ env.STATUS }}
+ STATUS_COLOR: ${{ env.STATUS_COLOR }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ update-ts: ${{ steps.slack-start.outputs.ts }}
+ payload-file-path: "./.github/scripts/slack-messages/deployment-completed.json"
+ step-outcome: ${{ steps.deploy.outcome }}
+```
+
+## Automatic Status Detection
+
+When you provide `step-outcome` input, the action automatically sets these environment variables:
+
+| Outcome | STATUS_EMOJI | STATUS_TEXT |
+|---------|--------------|-------------|
+| success | `[ā]` | `completed successfully!` |
+| failure | `[ā]` | `failed` |
+
+These variables are then available in your payload template files.
+
+## Template File Format
+
+All template files must be valid JSON and support environment variable substitution. Example:
+
+```json
+{
+ "channel": "$SLACK_CHANNEL_ID",
+ "text": "$STATUS_EMOJI $COMPONENT container release $RELEASE_TAG push $STATUS_TEXT <$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|View run>"
+}
+```
+
+See available templates in [`.github/scripts/slack-messages/`](../../scripts/slack-messages/).
+
+## Requirements
+
+- Slack Bot Token with scopes: `chat:write`, `chat:write.public`
+- Slack Channel ID where messages will be posted
+- JSON template files for your messages
+
+## Benefits
+
+- **Consistency**: All notifications use standardized templates
+- **Automatic status handling**: No need to calculate success/failure in workflows
+- **Clean workflows**: Minimal boilerplate code
+- **Reusable templates**: One template for all components
+- **Easy to maintain**: Change template once, applies everywhere
+- **Version controlled**: All message formats in git
+
+## Related Resources
+
+- [Slack Block Kit Builder](https://app.slack.com/block-kit-builder)
+- [Slack API Method Documentation](https://docs.slack.dev/tools/slack-github-action/sending-techniques/sending-data-slack-api-method/)
+- [Message templates documentation](../../scripts/slack-messages/README.md)
diff --git a/.github/actions/slack-notification/action.yml b/.github/actions/slack-notification/action.yml
new file mode 100644
index 0000000000..1427fed3e0
--- /dev/null
+++ b/.github/actions/slack-notification/action.yml
@@ -0,0 +1,74 @@
+name: 'Slack Notification'
+description: 'Generic action to send Slack notifications with optional message updates and automatic status detection'
+inputs:
+ slack-bot-token:
+ description: 'Slack bot token for authentication'
+ required: true
+ payload-file-path:
+ description: 'Path to JSON file with the Slack message payload'
+ required: true
+ update-ts:
+ description: 'Message timestamp to update (only for updates, leave empty for new messages)'
+ required: false
+ default: ''
+ step-outcome:
+ description: 'Outcome of a step to determine status (success/failure) - automatically sets STATUS_TEXT and STATUS_COLOR env vars'
+ required: false
+ default: ''
+outputs:
+ ts:
+ description: 'Timestamp of the Slack message'
+ value: ${{ steps.slack-notification.outputs.ts }}
+runs:
+ using: 'composite'
+ steps:
+ - name: Determine status
+ id: status
+ shell: bash
+ run: |
+ if [[ "${{ inputs.step-outcome }}" == "success" ]]; then
+ echo "STATUS_TEXT=Completed" >> $GITHUB_ENV
+ echo "STATUS_COLOR=#6aa84f" >> $GITHUB_ENV
+ elif [[ "${{ inputs.step-outcome }}" == "failure" ]]; then
+ echo "STATUS_TEXT=Failed" >> $GITHUB_ENV
+ echo "STATUS_COLOR=#fc3434" >> $GITHUB_ENV
+ else
+ # No outcome provided - pending/in progress state
+ echo "STATUS_COLOR=#dbab09" >> $GITHUB_ENV
+ fi
+
+ - name: Send Slack notification (new message)
+ if: inputs.update-ts == ''
+ id: slack-notification-post
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_PAYLOAD_FILE_PATH: ${{ inputs.payload-file-path }}
+ with:
+ method: chat.postMessage
+ token: ${{ inputs.slack-bot-token }}
+ payload-file-path: ${{ inputs.payload-file-path }}
+ payload-templated: true
+ errors: true
+
+ - name: Update Slack notification
+ if: inputs.update-ts != ''
+ id: slack-notification-update
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_PAYLOAD_FILE_PATH: ${{ inputs.payload-file-path }}
+ with:
+ method: chat.update
+ token: ${{ inputs.slack-bot-token }}
+ payload-file-path: ${{ inputs.payload-file-path }}
+ payload-templated: true
+ errors: true
+
+ - name: Set output
+ id: slack-notification
+ shell: bash
+ run: |
+ if [[ "${{ inputs.update-ts }}" == "" ]]; then
+ echo "ts=${{ steps.slack-notification-post.outputs.ts }}" >> $GITHUB_OUTPUT
+ else
+ echo "ts=${{ inputs.update-ts }}" >> $GITHUB_OUTPUT
+ fi
diff --git a/.github/actions/trivy-scan/action.yml b/.github/actions/trivy-scan/action.yml
new file mode 100644
index 0000000000..e3c2404748
--- /dev/null
+++ b/.github/actions/trivy-scan/action.yml
@@ -0,0 +1,164 @@
+name: 'Container Security Scan with Trivy'
+description: 'Scans container images for vulnerabilities using Trivy and reports results'
+author: 'Prowler'
+
+inputs:
+ image-name:
+ description: 'Container image name to scan'
+ required: true
+ image-tag:
+ description: 'Container image tag to scan'
+ required: true
+ default: ${{ github.sha }}
+ severity:
+ description: 'Severities to scan for (comma-separated)'
+ required: false
+ default: 'CRITICAL,HIGH,MEDIUM,LOW'
+ fail-on-critical:
+ description: 'Fail the build if critical vulnerabilities are found'
+ required: false
+ default: 'false'
+ upload-sarif:
+ description: 'Upload results to GitHub Security tab'
+ required: false
+ default: 'true'
+ create-pr-comment:
+ description: 'Create a comment on the PR with scan results'
+ required: false
+ default: 'true'
+ artifact-retention-days:
+ description: 'Days to retain the Trivy report artifact'
+ required: false
+ default: '2'
+
+outputs:
+ critical-count:
+ description: 'Number of critical vulnerabilities found'
+ value: ${{ steps.security-check.outputs.critical }}
+ high-count:
+ description: 'Number of high vulnerabilities found'
+ value: ${{ steps.security-check.outputs.high }}
+ total-count:
+ description: 'Total number of vulnerabilities found'
+ value: ${{ steps.security-check.outputs.total }}
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Cache Trivy vulnerability database
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
+ with:
+ path: ~/.cache/trivy
+ key: trivy-db-${{ runner.os }}-${{ github.run_id }}
+ restore-keys: |
+ trivy-db-${{ runner.os }}-
+
+ - name: Run Trivy vulnerability scan (JSON)
+ uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # v0.33.1
+ with:
+ image-ref: ${{ inputs.image-name }}:${{ inputs.image-tag }}
+ format: 'json'
+ output: 'trivy-report.json'
+ severity: ${{ inputs.severity }}
+ exit-code: '0'
+ scanners: 'vuln'
+ timeout: '5m'
+
+ - name: Run Trivy vulnerability scan (SARIF)
+ if: inputs.upload-sarif == 'true' && github.event_name == 'push'
+ uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # v0.33.1
+ with:
+ image-ref: ${{ inputs.image-name }}:${{ inputs.image-tag }}
+ format: 'sarif'
+ output: 'trivy-results.sarif'
+ severity: 'CRITICAL,HIGH'
+ exit-code: '0'
+ scanners: 'vuln'
+ timeout: '5m'
+
+ - name: Upload Trivy results to GitHub Security tab
+ if: inputs.upload-sarif == 'true' && github.event_name == 'push'
+ uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
+ with:
+ sarif_file: 'trivy-results.sarif'
+ category: 'trivy-container'
+
+ - name: Upload Trivy report artifact
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ if: always()
+ with:
+ name: trivy-scan-report-${{ inputs.image-name }}
+ path: trivy-report.json
+ retention-days: ${{ inputs.artifact-retention-days }}
+
+ - name: Generate security summary
+ id: security-check
+ shell: bash
+ run: |
+ CRITICAL=$(jq '[.Results[]?.Vulnerabilities[]? | select(.Severity=="CRITICAL")] | length' trivy-report.json)
+ HIGH=$(jq '[.Results[]?.Vulnerabilities[]? | select(.Severity=="HIGH")] | length' trivy-report.json)
+ TOTAL=$(jq '[.Results[]?.Vulnerabilities[]?] | length' trivy-report.json)
+
+ echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
+ echo "high=$HIGH" >> $GITHUB_OUTPUT
+ echo "total=$TOTAL" >> $GITHUB_OUTPUT
+
+ echo "### š Container Security Scan" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Image:** \`${{ inputs.image-name }}:${{ inputs.image-tag }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "- š“ Critical: $CRITICAL" >> $GITHUB_STEP_SUMMARY
+ echo "- š High: $HIGH" >> $GITHUB_STEP_SUMMARY
+ echo "- **Total**: $TOTAL" >> $GITHUB_STEP_SUMMARY
+
+ - name: Comment scan results on PR
+ if: inputs.create-pr-comment == 'true' && github.event_name == 'pull_request'
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
+ env:
+ IMAGE_NAME: ${{ inputs.image-name }}
+ GITHUB_SHA: ${{ inputs.image-tag }}
+ SEVERITY: ${{ inputs.severity }}
+ with:
+ script: |
+ const comment = require('./.github/scripts/trivy-pr-comment.js');
+
+ // Unique identifier to find our comment
+ const marker = '';
+ const body = marker + '\n' + comment;
+
+ // Find existing comment
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ });
+
+ const existingComment = comments.find(c => c.body?.includes(marker));
+
+ if (existingComment) {
+ // Update existing comment
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existingComment.id,
+ body: body
+ });
+ console.log('ā
Updated existing Trivy scan comment');
+ } else {
+ // Create new comment
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: body
+ });
+ console.log('ā
Created new Trivy scan comment');
+ }
+
+ - name: Check for critical vulnerabilities
+ if: inputs.fail-on-critical == 'true' && steps.security-check.outputs.critical != '0'
+ shell: bash
+ run: |
+ echo "::error::Found ${{ steps.security-check.outputs.critical }} critical vulnerabilities"
+ echo "::warning::Please update packages or use a different base image"
+ exit 1
diff --git a/.github/codeql/api-codeql-config.yml b/.github/codeql/api-codeql-config.yml
index 9ce26a3651..0925ea4a33 100644
--- a/.github/codeql/api-codeql-config.yml
+++ b/.github/codeql/api-codeql-config.yml
@@ -1,3 +1,12 @@
-name: "API - CodeQL Config"
+name: 'API: CodeQL Config'
paths:
- - "api/"
+ - 'api/'
+
+paths-ignore:
+ - 'api/tests/**'
+ - 'api/**/__pycache__/**'
+ - 'api/**/migrations/**'
+ - 'api/**/*.md'
+
+queries:
+ - uses: security-and-quality
diff --git a/.github/codeql/sdk-codeql-config.yml b/.github/codeql/sdk-codeql-config.yml
index 7982398f42..4c933ecbda 100644
--- a/.github/codeql/sdk-codeql-config.yml
+++ b/.github/codeql/sdk-codeql-config.yml
@@ -1,4 +1,18 @@
-name: "SDK - CodeQL Config"
+name: 'SDK: CodeQL Config'
+paths:
+ - 'prowler/'
+
paths-ignore:
- - "api/"
- - "ui/"
+ - 'api/'
+ - 'ui/'
+ - 'dashboard/'
+ - 'mcp_server/'
+ - 'tests/**'
+ - 'util/**'
+ - 'contrib/**'
+ - 'examples/**'
+ - 'prowler/**/__pycache__/**'
+ - 'prowler/**/*.md'
+
+queries:
+ - uses: security-and-quality
diff --git a/.github/codeql/ui-codeql-config.yml b/.github/codeql/ui-codeql-config.yml
index fa4f80cae5..2eb4eebe87 100644
--- a/.github/codeql/ui-codeql-config.yml
+++ b/.github/codeql/ui-codeql-config.yml
@@ -1,3 +1,17 @@
-name: "UI - CodeQL Config"
+name: 'UI: CodeQL Config'
paths:
- - "ui/"
+ - 'ui/'
+
+paths-ignore:
+ - 'ui/node_modules/**'
+ - 'ui/.next/**'
+ - 'ui/out/**'
+ - 'ui/tests/**'
+ - 'ui/**/*.test.ts'
+ - 'ui/**/*.test.tsx'
+ - 'ui/**/*.spec.ts'
+ - 'ui/**/*.spec.tsx'
+ - 'ui/**/*.md'
+
+queries:
+ - uses: security-and-quality
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 688992e7e6..9a56691628 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -37,6 +37,16 @@ provider/iac:
- any-glob-to-any-file: "prowler/providers/iac/**"
- any-glob-to-any-file: "tests/providers/iac/**"
+provider/mongodbatlas:
+ - changed-files:
+ - any-glob-to-any-file: "prowler/providers/mongodbatlas/**"
+ - any-glob-to-any-file: "tests/providers/mongodbatlas/**"
+
+provider/oci:
+ - changed-files:
+ - any-glob-to-any-file: "prowler/providers/oraclecloud/**"
+ - any-glob-to-any-file: "tests/providers/oraclecloud/**"
+
github_actions:
- changed-files:
- any-glob-to-any-file: ".github/workflows/*"
@@ -52,11 +62,13 @@ mutelist:
- any-glob-to-any-file: "prowler/providers/azure/lib/mutelist/**"
- any-glob-to-any-file: "prowler/providers/gcp/lib/mutelist/**"
- any-glob-to-any-file: "prowler/providers/kubernetes/lib/mutelist/**"
+ - any-glob-to-any-file: "prowler/providers/mongodbatlas/lib/mutelist/**"
- any-glob-to-any-file: "tests/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/aws/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/azure/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/gcp/lib/mutelist/**"
- any-glob-to-any-file: "tests/providers/kubernetes/lib/mutelist/**"
+ - any-glob-to-any-file: "tests/providers/mongodbatlas/lib/mutelist/**"
integration/s3:
- changed-files:
@@ -103,6 +115,10 @@ component/ui:
- changed-files:
- any-glob-to-any-file: "ui/**"
+component/mcp-server:
+ - changed-files:
+ - any-glob-to-any-file: "mcp_server/**"
+
compliance:
- changed-files:
- any-glob-to-any-file: "prowler/compliance/**"
@@ -112,3 +128,7 @@ compliance:
review-django-migrations:
- changed-files:
- any-glob-to-any-file: "api/src/backend/api/migrations/**"
+
+metadata-review:
+ - changed-files:
+ - any-glob-to-any-file: "**/*.metadata.json"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 94122d8349..497c4d6214 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -22,6 +22,13 @@ Please add a detailed description of how to review this PR.
- [ ] Review if is needed to change the [Readme.md](https://github.com/prowler-cloud/prowler/blob/master/README.md)
- [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/prowler/CHANGELOG.md), if applicable.
+#### UI
+- [ ] All issue/task requirements work as expected on the UI
+- [ ] Screenshots/Video of the functionality flow (if applicable) - Mobile (X < 640px)
+- [ ] Screenshots/Video of the functionality flow (if applicable) - Table (640px > X < 1024px)
+- [ ] Screenshots/Video of the functionality flow (if applicable) - Desktop (X > 1024px)
+- [ ] Ensure new entries are added to [CHANGELOG.md](https://github.com/prowler-cloud/prowler/blob/master/ui/CHANGELOG.md), if applicable.
+
#### API
- [ ] Verify if API specs need to be regenerated.
- [ ] Check if version updates are required (e.g., specs, Poetry, etc.).
diff --git a/.github/scripts/slack-messages/README.md b/.github/scripts/slack-messages/README.md
new file mode 100644
index 0000000000..e7fcf00fdd
--- /dev/null
+++ b/.github/scripts/slack-messages/README.md
@@ -0,0 +1,462 @@
+# Slack Message Templates
+
+This directory contains reusable message templates for Slack notifications sent from GitHub Actions workflows.
+
+## Usage
+
+These JSON templates are used with the `slackapi/slack-github-action` using the Slack API method (`chat.postMessage` and `chat.update`). All templates support rich Block Kit formatting and message updates.
+
+### Available Templates
+
+**Container Releases**
+- `container-release-started.json`: Simple one-line notification when container push starts
+- `container-release-completed.json`: Simple one-line notification when container release completes
+
+**Deployments**
+- `deployment-started.json`: Deployment start notification with Block Kit formatting
+- `deployment-completed.json`: Deployment completion notification (updates the start message)
+
+All templates use the Slack API method and require a Slack Bot Token.
+
+## Setup Requirements
+
+1. Create a Slack App (or use existing)
+2. Add Bot Token Scopes: `chat:write`, `chat:write.public`
+3. Install the app to your workspace
+4. Get the Bot Token from OAuth & Permissions page
+5. Add secrets:
+ - `SLACK_BOT_TOKEN`: Your bot token
+ - `SLACK_CHANNEL_ID`: The channel ID where messages will be posted
+
+Reference: [Sending data using a Slack API method](https://docs.slack.dev/tools/slack-github-action/sending-techniques/sending-data-slack-api-method/)
+
+## Environment Variables
+
+### Required Secrets (GitHub Secrets)
+- `SLACK_BOT_TOKEN`: Passed as `token` parameter to the action (not as env variable)
+- `SLACK_CHANNEL_ID`: Used in payload as env variable
+
+### Container Release Variables (configured as env)
+- `COMPONENT`: Component name (e.g., "API", "SDK", "UI", "MCP")
+- `RELEASE_TAG` / `PROWLER_VERSION`: The release tag or version being deployed
+- `GITHUB_SERVER_URL`: Provided by GitHub context
+- `GITHUB_REPOSITORY`: Provided by GitHub context
+- `GITHUB_RUN_ID`: Provided by GitHub context
+- `STATUS_EMOJI`: Status symbol (calculated: `[ā]` for success, `[ā]` for failure)
+- `STATUS_TEXT`: Status text (calculated: "completed successfully!" or "failed")
+
+### Deployment Variables (configured as env)
+- `COMPONENT`: Component name (e.g., "API", "SDK", "UI", "MCP")
+- `ENVIRONMENT`: Environment name (e.g., "DEVELOPMENT", "PRODUCTION")
+- `COMMIT_HASH`: Commit hash being deployed
+- `VERSION_DEPLOYED`: Version being deployed
+- `GITHUB_ACTOR`: User who triggered the workflow
+- `GITHUB_WORKFLOW`: Workflow name
+- `GITHUB_SERVER_URL`: Provided by GitHub context
+- `GITHUB_REPOSITORY`: Provided by GitHub context
+- `GITHUB_RUN_ID`: Provided by GitHub context
+
+All other variables (MESSAGE_TS, STATUS, STATUS_COLOR, STATUS_EMOJI, etc.) are calculated internally within the workflow and should NOT be configured as environment variables.
+
+## Example Workflow Usage
+
+### Using the Generic Slack Notification Action (Recommended)
+
+**Recommended approach**: Use the generic reusable action `.github/actions/slack-notification` which provides maximum flexibility:
+
+#### Example 1: Container Release (Start + Completion)
+
+```yaml
+# Send start notification
+- name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload: |
+ {
+ "channel": "${{ secrets.SLACK_CHANNEL_ID }}",
+ "text": "API container release ${{ env.RELEASE_TAG }} push started... <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>"
+ }
+
+# Build and push container
+- name: Build and push container
+ if: github.event_name == 'release'
+ id: container-push
+ uses: docker/build-push-action@...
+ with:
+ push: true
+ tags: ...
+
+# Calculate status
+- name: Determine push status
+ if: github.event_name == 'release' && always()
+ id: push-status
+ run: |
+ if [[ "${{ steps.container-push.outcome }}" == "success" ]]; then
+ echo "emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "text=completed successfully!" >> $GITHUB_OUTPUT
+ else
+ echo "emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "text=failed" >> $GITHUB_OUTPUT
+ fi
+
+# Send completion notification
+- name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload: |
+ {
+ "channel": "${{ secrets.SLACK_CHANNEL_ID }}",
+ "text": "${{ steps.push-status.outputs.emoji }} API container release ${{ env.RELEASE_TAG }} push ${{ steps.push-status.outputs.text }} <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>"
+ }
+```
+
+#### Example 2: Simple One-Time Message
+
+```yaml
+- name: Send notification
+ uses: ./.github/actions/slack-notification
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload: |
+ {
+ "channel": "${{ secrets.SLACK_CHANNEL_ID }}",
+ "text": "Deployment completed successfully!"
+ }
+```
+
+#### Example 3: Deployment with Message Update Pattern
+
+```yaml
+# Send initial deployment message
+- name: Notify deployment started
+ id: slack-start
+ uses: ./.github/actions/slack-notification
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload: |
+ {
+ "channel": "${{ secrets.SLACK_CHANNEL_ID }}",
+ "text": "API deployment to PRODUCTION started",
+ "attachments": [
+ {
+ "color": "dbab09",
+ "blocks": [
+ {
+ "type": "header",
+ "text": {
+ "type": "plain_text",
+ "text": "API | Deployment to PRODUCTION"
+ }
+ },
+ {
+ "type": "section",
+ "fields": [
+ {
+ "type": "mrkdwn",
+ "text": "*Status:*\nIn Progress"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+# Run deployment
+- name: Deploy
+ id: deploy
+ run: terraform apply -auto-approve
+
+# Calculate status
+- name: Determine status
+ if: always()
+ id: status
+ run: |
+ if [[ "${{ steps.deploy.outcome }}" == "success" ]]; then
+ echo "color=28a745" >> $GITHUB_OUTPUT
+ echo "emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "status=Completed" >> $GITHUB_OUTPUT
+ else
+ echo "color=fc3434" >> $GITHUB_OUTPUT
+ echo "emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "status=Failed" >> $GITHUB_OUTPUT
+ fi
+
+# Update the same message with final status
+- name: Update deployment notification
+ if: always()
+ uses: ./.github/actions/slack-notification
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ update-ts: ${{ steps.slack-start.outputs.ts }}
+ payload: |
+ {
+ "channel": "${{ secrets.SLACK_CHANNEL_ID }}",
+ "ts": "${{ steps.slack-start.outputs.ts }}",
+ "text": "${{ steps.status.outputs.emoji }} API deployment to PRODUCTION ${{ steps.status.outputs.status }}",
+ "attachments": [
+ {
+ "color": "${{ steps.status.outputs.color }}",
+ "blocks": [
+ {
+ "type": "header",
+ "text": {
+ "type": "plain_text",
+ "text": "API | Deployment to PRODUCTION"
+ }
+ },
+ {
+ "type": "section",
+ "fields": [
+ {
+ "type": "mrkdwn",
+ "text": "*Status:*\n${{ steps.status.outputs.emoji }} ${{ steps.status.outputs.status }}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+```
+
+**Benefits of using the generic action:**
+- Maximum flexibility: Build any payload you need directly in the workflow
+- No template files needed: Everything inline
+- Supports all scenarios: one-time messages, start/update patterns, rich Block Kit
+- Easy to customize per use case
+- Generic: Works for containers, deployments, or any notification type
+
+For more details, see [Slack Notification Action](../../actions/slack-notification/README.md).
+
+### Using Message Templates (Alternative Approach)
+
+Simple one-line notifications for container releases:
+
+```yaml
+# Step 1: Notify when push starts
+- name: Notify container push started
+ if: github.event_name == 'release'
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ method: chat.postMessage
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+# Step 2: Build and push container
+- name: Build and push container
+ id: container-push
+ uses: docker/build-push-action@...
+ with:
+ push: true
+ tags: ...
+
+# Step 3: Determine push status
+- name: Determine push status
+ if: github.event_name == 'release' && always()
+ id: push-status
+ run: |
+ if [[ "${{ steps.container-push.outcome }}" == "success" ]]; then
+ echo "status-emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "status-text=completed successfully!" >> $GITHUB_OUTPUT
+ else
+ echo "status-emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "status-text=failed" >> $GITHUB_OUTPUT
+ fi
+
+# Step 4: Notify when push completes (success or failure)
+- name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ STATUS_EMOJI: ${{ steps.push-status.outputs.status-emoji }}
+ STATUS_TEXT: ${{ steps.push-status.outputs.status-text }}
+ with:
+ method: chat.postMessage
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+```
+
+### Deployment with Update Pattern
+
+For deployments that start with one message and update it with the final status:
+
+```yaml
+# Step 1: Send deployment start notification
+- name: Notify Deployment Start
+ id: slack-notification-start
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ COMPONENT: API
+ ENVIRONMENT: PRODUCTION
+ COMMIT_HASH: ${{ github.sha }}
+ VERSION_DEPLOYED: latest
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_WORKFLOW: ${{ github.workflow }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ method: chat.postMessage
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/deployment-started.json"
+
+# Step 2: Run your deployment steps
+- name: Terraform Plan
+ id: terraform-plan
+ run: terraform plan
+
+- name: Terraform Apply
+ id: terraform-apply
+ run: terraform apply -auto-approve
+
+# Step 3: Determine status (calculated internally, not configured)
+- name: Determine Status
+ if: always()
+ id: determine-status
+ run: |
+ if [[ "${{ steps.terraform-apply.outcome }}" == "success" ]]; then
+ echo "status=Completed" >> $GITHUB_OUTPUT
+ echo "status-color=28a745" >> $GITHUB_OUTPUT
+ echo "status-emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "plan-emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "apply-emoji=[ā]" >> $GITHUB_OUTPUT
+ elif [[ "${{ steps.terraform-plan.outcome }}" == "failure" || "${{ steps.terraform-apply.outcome }}" == "failure" ]]; then
+ echo "status=Failed" >> $GITHUB_OUTPUT
+ echo "status-color=fc3434" >> $GITHUB_OUTPUT
+ echo "status-emoji=[ā]" >> $GITHUB_OUTPUT
+ if [[ "${{ steps.terraform-plan.outcome }}" == "failure" ]]; then
+ echo "plan-emoji=[ā]" >> $GITHUB_OUTPUT
+ else
+ echo "plan-emoji=[ā]" >> $GITHUB_OUTPUT
+ fi
+ if [[ "${{ steps.terraform-apply.outcome }}" == "failure" ]]; then
+ echo "apply-emoji=[ā]" >> $GITHUB_OUTPUT
+ else
+ echo "apply-emoji=[ā]" >> $GITHUB_OUTPUT
+ fi
+ else
+ echo "status=Failed" >> $GITHUB_OUTPUT
+ echo "status-color=fc3434" >> $GITHUB_OUTPUT
+ echo "status-emoji=[ā]" >> $GITHUB_OUTPUT
+ echo "plan-emoji=[?]" >> $GITHUB_OUTPUT
+ echo "apply-emoji=[?]" >> $GITHUB_OUTPUT
+ fi
+
+# Step 4: Update the same Slack message (using calculated values)
+- name: Notify Deployment Result
+ if: always()
+ uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
+ MESSAGE_TS: ${{ steps.slack-notification-start.outputs.ts }}
+ COMPONENT: API
+ ENVIRONMENT: PRODUCTION
+ COMMIT_HASH: ${{ github.sha }}
+ VERSION_DEPLOYED: latest
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_WORKFLOW: ${{ github.workflow }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ STATUS: ${{ steps.determine-status.outputs.status }}
+ STATUS_COLOR: ${{ steps.determine-status.outputs.status-color }}
+ STATUS_EMOJI: ${{ steps.determine-status.outputs.status-emoji }}
+ PLAN_EMOJI: ${{ steps.determine-status.outputs.plan-emoji }}
+ APPLY_EMOJI: ${{ steps.determine-status.outputs.apply-emoji }}
+ TERRAFORM_PLAN_OUTCOME: ${{ steps.terraform-plan.outcome }}
+ TERRAFORM_APPLY_OUTCOME: ${{ steps.terraform-apply.outcome }}
+ with:
+ method: chat.update
+ token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/deployment-completed.json"
+```
+
+**Note**: Variables like `STATUS`, `STATUS_COLOR`, `STATUS_EMOJI`, `PLAN_EMOJI`, `APPLY_EMOJI` are calculated by the `determine-status` step based on the outcomes of previous steps. They should NOT be manually configured.
+
+## Key Features
+
+### Benefits of Using Slack API Method
+
+- **Rich Block Kit Formatting**: Full support for Slack's Block Kit including headers, sections, fields, colors, and attachments
+- **Message Updates**: Update the same message instead of posting multiple messages (using `chat.update` with `ts`)
+- **Consistent Experience**: Same look and feel as Prowler Cloud notifications
+- **Flexible**: Easy to customize message appearance by editing JSON templates
+
+### Differences from Webhook Method
+
+| Feature | webhook-trigger | Slack API (chat.postMessage) |
+|---------|-----------------|------------------------------|
+| Setup | Workflow Builder webhook | Slack Bot Token + Channel ID |
+| Formatting | Plain text/simple | Full Block Kit support |
+| Message Update | No | Yes (with chat.update) |
+| Authentication | Webhook URL | Bot Token |
+| Scopes Required | None | chat:write, chat:write.public |
+
+## Message Appearance
+
+### Container Release (Simple One-Line)
+
+**Start message:**
+```
+API container release 4.5.0 push started... View run
+```
+
+**Completion message (success):**
+```
+[ā] API container release 4.5.0 push completed successfully! View run
+```
+
+**Completion message (failure):**
+```
+[ā] API container release 4.5.0 push failed View run
+```
+
+All messages are simple one-liners with a clickable "View run" link. The completion message adapts to show success `[ā]` or failure `[ā]` based on the outcome of the container push.
+
+### Deployment Start
+- Header: Component and environment
+- Yellow bar (color: `dbab09`)
+- Status: In Progress
+- Details: Commit, version, actor, workflow
+- Link: Direct link to deployment run
+
+### Deployment Completion
+- Header: Component and environment
+- Green bar for success (color: `28a745`) / Red bar for failure (color: `fc3434`)
+- Status: [ā] Completed or [ā] Failed
+- Details: All deployment info plus terraform outcomes
+- Link: Direct link to deployment run
+
+## Adding New Templates
+
+1. Create a new JSON file with Block Kit structure
+2. Use environment variable placeholders (e.g., `$VAR_NAME`)
+3. Include `channel` and `text` fields (required)
+4. Add `blocks` or `attachments` for rich formatting
+5. For update templates, include `ts` field as `$MESSAGE_TS`
+6. Document the template in this README
+7. Reference it in your workflow using `payload-file-path`
+
+## Reference
+
+- [Slack Block Kit Builder](https://app.slack.com/block-kit-builder)
+- [Slack API Method Documentation](https://docs.slack.dev/tools/slack-github-action/sending-techniques/sending-data-slack-api-method/)
diff --git a/.github/scripts/slack-messages/container-release-completed.json b/.github/scripts/slack-messages/container-release-completed.json
new file mode 100644
index 0000000000..c1fc147191
--- /dev/null
+++ b/.github/scripts/slack-messages/container-release-completed.json
@@ -0,0 +1,17 @@
+{
+ "channel": "${{ env.SLACK_CHANNEL_ID }}",
+ "attachments": [
+ {
+ "color": "${{ env.STATUS_COLOR }}",
+ "blocks": [
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": "*Status:*\n${{ env.STATUS_TEXT }}\n\n${{ env.COMPONENT }} container release ${{ env.RELEASE_TAG }} push ${{ env.STATUS_TEXT }}\n\n<${{ env.GITHUB_SERVER_URL }}/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }}|View run>"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/scripts/slack-messages/container-release-started.json b/.github/scripts/slack-messages/container-release-started.json
new file mode 100644
index 0000000000..f67129e3ba
--- /dev/null
+++ b/.github/scripts/slack-messages/container-release-started.json
@@ -0,0 +1,17 @@
+{
+ "channel": "${{ env.SLACK_CHANNEL_ID }}",
+ "attachments": [
+ {
+ "color": "${{ env.STATUS_COLOR }}",
+ "blocks": [
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": "*Status:*\nStarted\n\n${{ env.COMPONENT }} container release ${{ env.RELEASE_TAG }} push started...\n\n<${{ env.GITHUB_SERVER_URL }}/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }}|View run>"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/scripts/trivy-pr-comment.js b/.github/scripts/trivy-pr-comment.js
new file mode 100644
index 0000000000..eb725b1af1
--- /dev/null
+++ b/.github/scripts/trivy-pr-comment.js
@@ -0,0 +1,102 @@
+const fs = require('fs');
+
+// Configuration from environment variables
+const REPORT_FILE = process.env.TRIVY_REPORT_FILE || 'trivy-report.json';
+const IMAGE_NAME = process.env.IMAGE_NAME || 'container-image';
+const GITHUB_SHA = process.env.GITHUB_SHA || 'unknown';
+const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY || '';
+const GITHUB_RUN_ID = process.env.GITHUB_RUN_ID || '';
+const SEVERITY = process.env.SEVERITY || 'CRITICAL,HIGH,MEDIUM,LOW';
+
+// Parse severities to scan
+const scannedSeverities = SEVERITY.split(',').map(s => s.trim());
+
+// Read and parse the Trivy report
+const report = JSON.parse(fs.readFileSync(REPORT_FILE, 'utf-8'));
+
+let vulnCount = 0;
+let vulnsByType = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
+let affectedPackages = new Set();
+
+if (report.Results && Array.isArray(report.Results)) {
+ for (const result of report.Results) {
+ if (result.Vulnerabilities && Array.isArray(result.Vulnerabilities)) {
+ for (const vuln of result.Vulnerabilities) {
+ vulnCount++;
+ if (vulnsByType[vuln.Severity] !== undefined) {
+ vulnsByType[vuln.Severity]++;
+ }
+ if (vuln.PkgName) {
+ affectedPackages.add(vuln.PkgName);
+ }
+ }
+ }
+ }
+}
+
+const shortSha = GITHUB_SHA.substring(0, 7);
+const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19) + ' UTC';
+
+// Severity icons and labels
+const severityConfig = {
+ CRITICAL: { icon: 'š“', label: 'Critical' },
+ HIGH: { icon: 'š ', label: 'High' },
+ MEDIUM: { icon: 'š”', label: 'Medium' },
+ LOW: { icon: 'šµ', label: 'Low' }
+};
+
+let comment = '## š Container Security Scan\n\n';
+comment += `**Image:** \`${IMAGE_NAME}:${shortSha}\`\n`;
+comment += `**Last scan:** ${timestamp}\n\n`;
+
+if (vulnCount === 0) {
+ comment += '### ā
No Vulnerabilities Detected\n\n';
+ comment += 'The container image passed all security checks. No known CVEs were found.\n';
+} else {
+ comment += '### š Vulnerability Summary\n\n';
+ comment += '| Severity | Count |\n';
+ comment += '|----------|-------|\n';
+
+ // Only show severities that were scanned
+ for (const severity of scannedSeverities) {
+ const config = severityConfig[severity];
+ const count = vulnsByType[severity] || 0;
+ const isBold = (severity === 'CRITICAL' || severity === 'HIGH') && count > 0;
+ const countDisplay = isBold ? `**${count}**` : count;
+ comment += `| ${config.icon} ${config.label} | ${countDisplay} |\n`;
+ }
+
+ comment += `| **Total** | **${vulnCount}** |\n\n`;
+
+ if (affectedPackages.size > 0) {
+ comment += `**${affectedPackages.size}** package(s) affected\n\n`;
+ }
+
+ if (vulnsByType.CRITICAL > 0) {
+ comment += '### ā ļø Action Required\n\n';
+ comment += '**Critical severity vulnerabilities detected.** These should be addressed before merging:\n';
+ comment += '- Review the detailed scan results\n';
+ comment += '- Update affected packages to patched versions\n';
+ comment += '- Consider using a different base image if updates are unavailable\n\n';
+ } else if (vulnsByType.HIGH > 0) {
+ comment += '### ā ļø Attention Needed\n\n';
+ comment += '**High severity vulnerabilities found.** Please review and plan remediation:\n';
+ comment += '- Assess the risk and exploitability\n';
+ comment += '- Prioritize updates in the next maintenance cycle\n\n';
+ } else {
+ comment += '### ā¹ļø Review Recommended\n\n';
+ comment += 'Medium/Low severity vulnerabilities found. Consider addressing during regular maintenance.\n\n';
+ }
+}
+
+comment += '---\n';
+comment += 'š **Resources:**\n';
+
+if (GITHUB_REPOSITORY && GITHUB_RUN_ID) {
+ comment += `- [Download full report](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) (see artifacts)\n`;
+}
+
+comment += '- [View in Security tab](https://github.com/' + (GITHUB_REPOSITORY || 'repository') + '/security/code-scanning)\n';
+comment += '- Scanned with [Trivy](https://github.com/aquasecurity/trivy)\n';
+
+module.exports = comment;
diff --git a/.github/workflows/api-build-lint-push-containers.yml b/.github/workflows/api-build-lint-push-containers.yml
deleted file mode 100644
index 0fe6d4a0b9..0000000000
--- a/.github/workflows/api-build-lint-push-containers.yml
+++ /dev/null
@@ -1,115 +0,0 @@
-name: API - Build and Push containers
-
-on:
- push:
- branches:
- - "master"
- paths:
- - "api/**"
- - "prowler/**"
- - ".github/workflows/api-build-lint-push-containers.yml"
-
- # Uncomment the code below to test this action on PRs
- # pull_request:
- # branches:
- # - "master"
- # paths:
- # - "api/**"
- # - ".github/workflows/api-build-lint-push-containers.yml"
-
- release:
- types: [published]
-
-env:
- # Tags
- LATEST_TAG: latest
- RELEASE_TAG: ${{ github.event.release.tag_name }}
- STABLE_TAG: stable
-
- WORKING_DIRECTORY: ./api
-
- # Container Registries
- PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
- PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-api
-
-jobs:
- repository-check:
- name: Repository check
- runs-on: ubuntu-latest
- outputs:
- is_repo: ${{ steps.repository_check.outputs.is_repo }}
- steps:
- - name: Repository check
- id: repository_check
- working-directory: /tmp
- run: |
- if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
- then
- echo "is_repo=true" >> "${GITHUB_OUTPUT}"
- else
- echo "This action only runs for prowler-cloud/prowler"
- echo "is_repo=false" >> "${GITHUB_OUTPUT}"
- fi
-
- # Build Prowler OSS container
- container-build-push:
- needs: repository-check
- if: needs.repository-check.outputs.is_repo == 'true'
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ${{ env.WORKING_DIRECTORY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Set short git commit SHA
- id: vars
- run: |
- shortSha=$(git rev-parse --short ${{ github.sha }})
- echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
-
- - name: Login to DockerHub
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
-
- - name: Build and push container image (latest)
- # Comment the following line for testing
- if: github.event_name == 'push'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.WORKING_DIRECTORY }}
- # Set push: false for testing
- push: true
- tags: |
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.SHORT_SHA }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- - name: Build and push container image (release)
- if: github.event_name == 'release'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.WORKING_DIRECTORY }}
- push: true
- tags: |
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- - name: Trigger deployment
- if: github.event_name == 'push'
- uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
- with:
- token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- repository: ${{ secrets.CLOUD_DISPATCH }}
- event-type: prowler-api-deploy
- client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ env.SHORT_SHA }}"}'
diff --git a/.github/workflows/api-code-quality.yml b/.github/workflows/api-code-quality.yml
new file mode 100644
index 0000000000..a9dddaa3aa
--- /dev/null
+++ b/.github/workflows/api-code-quality.yml
@@ -0,0 +1,71 @@
+name: 'API: Code Quality'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ API_WORKING_DIR: ./api
+
+jobs:
+ api-code-quality:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ python-version:
+ - '3.12'
+ defaults:
+ run:
+ working-directory: ./api
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for API changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ api/**
+ .github/workflows/api-code-quality.yml
+ files_ignore: |
+ api/docs/**
+ api/README.md
+ api/CHANGELOG.md
+
+ - name: Setup Python with Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/setup-python-poetry
+ with:
+ python-version: ${{ matrix.python-version }}
+ working-directory: ./api
+
+ - name: Poetry check
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry check --lock
+
+ - name: Ruff lint
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run ruff check . --exclude contrib
+
+ - name: Ruff format
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run ruff format --check . --exclude contrib
+
+ - name: Pylint
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run pylint --disable=W,C,R,E -j 0 -rn -sn src/
diff --git a/.github/workflows/api-codeql.yml b/.github/workflows/api-codeql.yml
index 8d0a81c8b6..16ea82538e 100644
--- a/.github/workflows/api-codeql.yml
+++ b/.github/workflows/api-codeql.yml
@@ -1,36 +1,34 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: API - CodeQL
+name: 'API: CodeQL'
on:
push:
branches:
- - "master"
- - "v5.*"
+ - 'master'
+ - 'v5.*'
paths:
- - "api/**"
+ - 'api/**'
+ - '.github/workflows/api-codeql.yml'
+ - '.github/codeql/api-codeql-config.yml'
pull_request:
branches:
- - "master"
- - "v5.*"
+ - 'master'
+ - 'v5.*'
paths:
- - "api/**"
+ - 'api/**'
+ - '.github/workflows/api-codeql.yml'
+ - '.github/codeql/api-codeql-config.yml'
schedule:
- cron: '00 12 * * *'
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
- analyze:
- name: Analyze
+ api-analyze:
+ name: CodeQL Security Analysis
runs-on: ubuntu-latest
+ timeout-minutes: 30
permissions:
actions: read
contents: read
@@ -39,21 +37,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: [ 'python' ]
- # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+ language:
+ - 'python'
steps:
- - name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
- with:
- languages: ${{ matrix.language }}
- config-file: ./.github/codeql/api-codeql-config.yml
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
+ with:
+ languages: ${{ matrix.language }}
+ config-file: ./.github/codeql/api-codeql-config.yml
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
- with:
- category: "/language:${{matrix.language}}"
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
+ with:
+ category: '/language:${{ matrix.language }}'
diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml
new file mode 100644
index 0000000000..3b3b4a4222
--- /dev/null
+++ b/.github/workflows/api-container-build-push.yml
@@ -0,0 +1,177 @@
+name: 'API: Container Build and Push'
+
+on:
+ push:
+ branches:
+ - 'master'
+ paths:
+ - 'api/**'
+ - 'prowler/**'
+ - '.github/workflows/api-build-lint-push-containers.yml'
+ release:
+ types:
+ - 'published'
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ # Tags
+ LATEST_TAG: latest
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
+ STABLE_TAG: stable
+ WORKING_DIRECTORY: ./api
+
+ # Container registries
+ PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
+ PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-api
+
+jobs:
+ setup:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ outputs:
+ short-sha: ${{ steps.set-short-sha.outputs.short-sha }}
+ steps:
+ - name: Calculate short SHA
+ id: set-short-sha
+ run: echo "short-sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
+
+ container-build-push:
+ needs: setup
+ runs-on: ${{ matrix.runner }}
+ strategy:
+ matrix:
+ include:
+ - platform: linux/amd64
+ runner: ubuntu-latest
+ arch: amd64
+ - platform: linux/arm64
+ runner: ubuntu-24.04-arm
+ arch: arm64
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Login to DockerHub
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build and push API container for ${{ matrix.arch }}
+ if: github.event_name == 'push' || github.event_name == 'release'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.WORKING_DIRECTORY }}
+ push: true
+ platforms: ${{ matrix.platform }}
+ tags: |
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-${{ matrix.arch }}
+ cache-from: type=gha,scope=${{ matrix.arch }}
+ cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
+
+ - name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+ - name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: API
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+ step-outcome: ${{ steps.container-push.outcome }}
+
+ # Create and push multi-architecture manifest
+ create-manifest:
+ needs: [setup, container-build-push]
+ if: github.event_name == 'push' || github.event_name == 'release'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Login to DockerHub
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Create and push manifests for push event
+ if: github.event_name == 'push'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Create and push manifests for release event
+ if: github.event_name == 'release'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Install regctl
+ if: always()
+ uses: regclient/actions/regctl-installer@f61d18f46c86af724a9c804cb9ff2a6fec741c7c # main
+
+ - name: Cleanup intermediate architecture tags
+ if: always()
+ run: |
+ echo "Cleaning up intermediate tags..."
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64" || true
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64" || true
+ echo "Cleanup completed"
+
+ trigger-deployment:
+ if: github.event_name == 'push'
+ needs: [setup, container-build-push]
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+
+ steps:
+ - name: Trigger API deployment
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ repository: ${{ secrets.CLOUD_DISPATCH }}
+ event-type: api-prowler-deployment
+ client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ needs.setup.outputs.short-sha }}"}'
diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml
new file mode 100644
index 0000000000..d069b0d5a6
--- /dev/null
+++ b/.github/workflows/api-container-checks.yml
@@ -0,0 +1,89 @@
+name: 'API: Container Checks'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ API_WORKING_DIR: ./api
+ IMAGE_NAME: prowler-api
+
+jobs:
+ api-dockerfile-lint:
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check if Dockerfile changed
+ id: dockerfile-changed
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: api/Dockerfile
+
+ - name: Lint Dockerfile with Hadolint
+ if: steps.dockerfile-changed.outputs.any_changed == 'true'
+ uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
+ with:
+ dockerfile: api/Dockerfile
+ ignore: DL3013
+
+ api-container-build-and-scan:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for API changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: api/**
+ files_ignore: |
+ api/docs/**
+ api/README.md
+ api/CHANGELOG.md
+
+ - name: Set up Docker Buildx
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build container
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.API_WORKING_DIR }}
+ push: false
+ load: true
+ tags: ${{ env.IMAGE_NAME }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Scan container with Trivy
+ if: github.repository == 'prowler-cloud/prowler' && steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/trivy-scan
+ with:
+ image-name: ${{ env.IMAGE_NAME }}
+ image-tag: ${{ github.sha }}
+ fail-on-critical: 'false'
+ severity: 'CRITICAL'
diff --git a/.github/workflows/api-pull-request.yml b/.github/workflows/api-pull-request.yml
deleted file mode 100644
index 339149f94b..0000000000
--- a/.github/workflows/api-pull-request.yml
+++ /dev/null
@@ -1,239 +0,0 @@
-name: API - Pull Request
-
-on:
- push:
- branches:
- - "master"
- - "v5.*"
- paths:
- - ".github/workflows/api-pull-request.yml"
- - "api/**"
- pull_request:
- branches:
- - "master"
- - "v5.*"
- paths:
- - ".github/workflows/api-pull-request.yml"
- - "api/**"
-
-env:
- POSTGRES_HOST: localhost
- POSTGRES_PORT: 5432
- POSTGRES_ADMIN_USER: prowler
- POSTGRES_ADMIN_PASSWORD: S3cret
- POSTGRES_USER: prowler_user
- POSTGRES_PASSWORD: prowler
- POSTGRES_DB: postgres-db
- VALKEY_HOST: localhost
- VALKEY_PORT: 6379
- VALKEY_DB: 0
- API_WORKING_DIR: ./api
- IMAGE_NAME: prowler-api
- IGNORE_FILES: |
- api/docs/**
- api/README.md
- api/CHANGELOG.md
-
-jobs:
- test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: ["3.12"]
-
- # Service containers to run with `test`
- services:
- # Label used to access the service container
- postgres:
- image: postgres
- env:
- POSTGRES_HOST: ${{ env.POSTGRES_HOST }}
- POSTGRES_PORT: ${{ env.POSTGRES_PORT }}
- POSTGRES_USER: ${{ env.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
- POSTGRES_DB: ${{ env.POSTGRES_DB }}
- # Set health checks to wait until postgres has started
- ports:
- - 5432:5432
- options: >-
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
- valkey:
- image: valkey/valkey:7-alpine3.19
- env:
- VALKEY_HOST: ${{ env.VALKEY_HOST }}
- VALKEY_PORT: ${{ env.VALKEY_PORT }}
- VALKEY_DB: ${{ env.VALKEY_DB }}
- # Set health checks to wait until postgres has started
- ports:
- - 6379:6379
- options: >-
- --health-cmd "valkey-cli ping"
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Test if changes are in not ignored paths
- id: are-non-ignored-files-changed
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- api/**
- .github/workflows/api-pull-request.yml
- files_ignore: ${{ env.IGNORE_FILES }}
-
- - name: Replace @master with current branch in pyproject.toml
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- BRANCH_NAME="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}"
- echo "Using branch: $BRANCH_NAME"
- sed -i "s|@master|@$BRANCH_NAME|g" pyproject.toml
-
- - name: Install poetry
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- python -m pip install --upgrade pip
- pipx install poetry==2.1.1
-
- - name: Update poetry.lock after the branch name change
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry lock
-
- - name: Update SDK's poetry.lock resolved_reference to latest commit - Only for push events to `master`
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' && github.event_name == 'push'
- run: |
- # Get the latest commit hash from the prowler-cloud/prowler repository
- LATEST_COMMIT=$(curl -s "https://api.github.com/repos/prowler-cloud/prowler/commits/master" | jq -r '.sha')
- echo "Latest commit hash: $LATEST_COMMIT"
-
- # Update the resolved_reference specifically for prowler-cloud/prowler repository
- sed -i '/url = "https:\/\/github\.com\/prowler-cloud\/prowler\.git"/,/resolved_reference = / {
- s/resolved_reference = "[a-f0-9]\{40\}"/resolved_reference = "'"$LATEST_COMMIT"'"/
- }' poetry.lock
-
- # Verify the change was made
- echo "Updated resolved_reference:"
- grep -A2 -B2 "resolved_reference" poetry.lock
-
- - name: Set up Python ${{ matrix.python-version }}
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- with:
- python-version: ${{ matrix.python-version }}
- cache: "poetry"
-
- - name: Install system dependencies for xmlsec
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- sudo apt-get update
- sudo apt-get install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl pkg-config
-
- - name: Install dependencies
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry install --no-root
- poetry run pip list
- VERSION=$(curl --silent "https://api.github.com/repos/hadolint/hadolint/releases/latest" | \
- grep '"tag_name":' | \
- sed -E 's/.*"v([^"]+)".*/\1/' \
- ) && curl -L -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64" \
- && chmod +x /tmp/hadolint
-
- - name: Poetry check
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry check --lock
-
- - name: Lint with ruff
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run ruff check . --exclude contrib
-
- - name: Check Format with ruff
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run ruff format --check . --exclude contrib
-
- - name: Lint with pylint
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run pylint --disable=W,C,R,E -j 0 -rn -sn src/
-
- - name: Bandit
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run bandit -q -lll -x '*_test.py,./contrib/' -r .
-
- - name: Safety
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- # 76352, 76353, 77323 come from SDK, but they cannot upgrade it yet. It does not affect API
- # TODO: Botocore needs urllib3 1.X so we need to ignore these vulnerabilities 77744,77745. Remove this once we upgrade to urllib3 2.X
- run: |
- poetry run safety check --ignore 70612,66963,74429,76352,76353,77323,77744,77745
-
- - name: Vulture
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run vulture --exclude "contrib,tests,conftest.py" --min-confidence 100 .
-
- - name: Hadolint
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- /tmp/hadolint Dockerfile --ignore=DL3013
-
- - name: Test with pytest
- working-directory: ./api
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run pytest --cov=./src/backend --cov-report=xml src/backend
-
- - name: Upload coverage reports to Codecov
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
- env:
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- with:
- flags: api
- test-container-build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Test if changes are in not ignored paths
- id: are-non-ignored-files-changed
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: api/**
- files_ignore: ${{ env.IGNORE_FILES }}
- - name: Set up Docker Buildx
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- - name: Build Container
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.API_WORKING_DIR }}
- push: false
- tags: ${{ env.IMAGE_NAME }}:latest
- outputs: type=docker
- cache-from: type=gha
- cache-to: type=gha,mode=max
diff --git a/.github/workflows/api-security.yml b/.github/workflows/api-security.yml
new file mode 100644
index 0000000000..33134ec9c9
--- /dev/null
+++ b/.github/workflows/api-security.yml
@@ -0,0 +1,69 @@
+name: 'API: Security'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ API_WORKING_DIR: ./api
+
+jobs:
+ api-security-scans:
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ python-version:
+ - '3.12'
+ defaults:
+ run:
+ working-directory: ./api
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for API changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ api/**
+ .github/workflows/api-security.yml
+ files_ignore: |
+ api/docs/**
+ api/README.md
+ api/CHANGELOG.md
+
+ - name: Setup Python with Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/setup-python-poetry
+ with:
+ python-version: ${{ matrix.python-version }}
+ working-directory: ./api
+
+ - name: Bandit
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run bandit -q -lll -x '*_test.py,./contrib/' -r .
+
+ - name: Safety
+ if: steps.check-changes.outputs.any_changed == 'true'
+ # 76352, 76353, 77323 come from SDK, but they cannot upgrade it yet. It does not affect API
+ # TODO: Botocore needs urllib3 1.X so we need to ignore these vulnerabilities 77744,77745. Remove this once we upgrade to urllib3 2.X
+ run: poetry run safety check --ignore 70612,66963,74429,76352,76353,77323,77744,77745
+
+ - name: Vulture
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run vulture --exclude "contrib,tests,conftest.py" --min-confidence 100 .
diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml
new file mode 100644
index 0000000000..daeb79abac
--- /dev/null
+++ b/.github/workflows/api-tests.yml
@@ -0,0 +1,107 @@
+name: 'API: Tests'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ POSTGRES_HOST: localhost
+ POSTGRES_PORT: 5432
+ POSTGRES_ADMIN_USER: prowler
+ POSTGRES_ADMIN_PASSWORD: S3cret
+ POSTGRES_USER: prowler_user
+ POSTGRES_PASSWORD: prowler
+ POSTGRES_DB: postgres-db
+ VALKEY_HOST: localhost
+ VALKEY_PORT: 6379
+ VALKEY_DB: 0
+ API_WORKING_DIR: ./api
+
+jobs:
+ api-tests:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ python-version:
+ - '3.12'
+ defaults:
+ run:
+ working-directory: ./api
+
+ services:
+ postgres:
+ image: postgres
+ env:
+ POSTGRES_HOST: ${{ env.POSTGRES_HOST }}
+ POSTGRES_PORT: ${{ env.POSTGRES_PORT }}
+ POSTGRES_USER: ${{ env.POSTGRES_USER }}
+ POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
+ POSTGRES_DB: ${{ env.POSTGRES_DB }}
+ ports:
+ - 5432:5432
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+ valkey:
+ image: valkey/valkey:7-alpine3.19
+ env:
+ VALKEY_HOST: ${{ env.VALKEY_HOST }}
+ VALKEY_PORT: ${{ env.VALKEY_PORT }}
+ VALKEY_DB: ${{ env.VALKEY_DB }}
+ ports:
+ - 6379:6379
+ options: >-
+ --health-cmd "valkey-cli ping"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for API changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ api/**
+ .github/workflows/api-tests.yml
+ files_ignore: |
+ api/docs/**
+ api/README.md
+ api/CHANGELOG.md
+
+ - name: Setup Python with Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/setup-python-poetry
+ with:
+ python-version: ${{ matrix.python-version }}
+ working-directory: ./api
+
+ - name: Run tests with pytest
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run pytest --cov=./src/backend --cov-report=xml src/backend
+
+ - name: Upload coverage reports to Codecov
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: api
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 2aa0a49c09..974d919fc6 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -1,28 +1,33 @@
-name: Prowler - Automatic Backport
+name: 'Tools: Backport'
on:
pull_request_target:
- branches: ['master']
- types: ['labeled', 'closed']
+ branches:
+ - 'master'
+ types:
+ - 'labeled'
+ - 'closed'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: false
env:
- # The prefix of the label that triggers the backport must not contain the branch name
- # so, for example, if the branch is 'master', the label should be 'backport-to-'
BACKPORT_LABEL_PREFIX: backport-to-
BACKPORT_LABEL_IGNORE: was-backported
jobs:
backport:
- name: Backport PR
if: github.event.pull_request.merged == true && !(contains(github.event.pull_request.labels.*.name, 'backport')) && !(contains(github.event.pull_request.labels.*.name, 'was-backported'))
runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
- id-token: write
- pull-requests: write
contents: write
+ pull-requests: write
+
steps:
- name: Check labels
- id: preview_label_check
+ id: label_check
uses: agilepathway/label-checker@c3d16ad512e7cea5961df85ff2486bb774caf3c5 # v1.6.65
with:
allow_failure: true
@@ -31,17 +36,17 @@ jobs:
none_of: ${{ env.BACKPORT_LABEL_IGNORE }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
- - name: Backport Action
- if: steps.preview_label_check.outputs.label_check == 'success'
- uses: sorenlouv/backport-github-action@ad888e978060bc1b2798690dd9d03c4036560947 # v9.5.1
+ - name: Backport PR
+ if: steps.label_check.outputs.label_check == 'success'
+ uses: sorenlouv/backport-github-action@516854e7c9f962b9939085c9a92ea28411d1ae90 # v10.2.0
with:
github_token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
auto_backport_label_prefix: ${{ env.BACKPORT_LABEL_PREFIX }}
- - name: Info log
- if: ${{ success() && steps.preview_label_check.outputs.label_check == 'success' }}
+ - name: Display backport info log
+ if: success() && steps.label_check.outputs.label_check == 'success'
run: cat ~/.backport/backport.info.log
- - name: Debug log
- if: ${{ failure() && steps.preview_label_check.outputs.label_check == 'success' }}
+ - name: Display backport debug log
+ if: failure() && steps.label_check.outputs.label_check == 'success'
run: cat ~/.backport/backport.debug.log
diff --git a/.github/workflows/build-documentation-on-pr.yml b/.github/workflows/build-documentation-on-pr.yml
deleted file mode 100644
index 20553b87af..0000000000
--- a/.github/workflows/build-documentation-on-pr.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Prowler - Pull Request Documentation Link
-
-on:
- pull_request:
- branches:
- - 'master'
- - 'v3'
- paths:
- - 'docs/**'
- - '.github/workflows/build-documentation-on-pr.yml'
-
-env:
- PR_NUMBER: ${{ github.event.pull_request.number }}
-
-jobs:
- documentation-link:
- name: Documentation Link
- runs-on: ubuntu-latest
- steps:
- - name: Find existing documentation comment
- uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
- id: find-comment
- with:
- issue-number: ${{ env.PR_NUMBER }}
- comment-author: 'github-actions[bot]'
- body-includes: ''
-
- - name: Create or update PR comment with the Prowler Documentation URI
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
- with:
- comment-id: ${{ steps.find-comment.outputs.comment-id }}
- issue-number: ${{ env.PR_NUMBER }}
- body: |
-
- You can check the documentation for this PR here -> [Prowler Documentation](https://prowler-prowler-docs--${{ env.PR_NUMBER }}.com.readthedocs.build/projects/prowler-open-source/en/${{ env.PR_NUMBER }}/)
- edit-mode: replace
diff --git a/.github/workflows/comment-label-update.yml b/.github/workflows/comment-label-update.yml
new file mode 100644
index 0000000000..9bddd6a9dd
--- /dev/null
+++ b/.github/workflows/comment-label-update.yml
@@ -0,0 +1,39 @@
+name: 'Tools: Comment Label Update'
+
+on:
+ issue_comment:
+ types:
+ - 'created'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.issue.number }}
+ cancel-in-progress: false
+
+jobs:
+ update-labels:
+ if: contains(github.event.issue.labels.*.name, 'status/awaiting-response')
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ issues: write
+ pull-requests: write
+
+ steps:
+ - name: Remove 'status/awaiting-response' label
+ env:
+ GH_TOKEN: ${{ github.token }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
+ run: |
+ echo "Removing 'status/awaiting-response' label from #$ISSUE_NUMBER"
+ gh api /repos/${{ github.repository }}/issues/$ISSUE_NUMBER/labels/status%2Fawaiting-response \
+ -X DELETE
+
+ - name: Add 'status/waiting-for-revision' label
+ env:
+ GH_TOKEN: ${{ github.token }}
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
+ run: |
+ echo "Adding 'status/waiting-for-revision' label to #$ISSUE_NUMBER"
+ gh api /repos/${{ github.repository }}/issues/$ISSUE_NUMBER/labels \
+ -X POST \
+ -f labels[]='status/waiting-for-revision'
diff --git a/.github/workflows/conventional-commit.yml b/.github/workflows/conventional-commit.yml
index cdc3e52de5..58e1653b74 100644
--- a/.github/workflows/conventional-commit.yml
+++ b/.github/workflows/conventional-commit.yml
@@ -1,23 +1,31 @@
-name: Prowler - Conventional Commit
+name: 'Tools: Conventional Commit'
on:
pull_request:
- types:
- - "opened"
- - "edited"
- - "synchronize"
branches:
- - "master"
- - "v3"
- - "v4.*"
- - "v5.*"
+ - 'master'
+ - 'v3'
+ - 'v4.*'
+ - 'v5.*'
+ types:
+ - 'opened'
+ - 'edited'
+ - 'synchronize'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
jobs:
conventional-commit-check:
runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ pull-requests: read
+
steps:
- - name: conventional-commit-check
- id: conventional-commit-check
- uses: agenthunt/conventional-commit-checker-action@9e552d650d0e205553ec7792d447929fc78e012b # v2.0.0
+ - name: Check PR title format
+ uses: agenthunt/conventional-commit-checker-action@f1823f632e95a64547566dcd2c7da920e67117ad # v2.0.1
with:
- pr-title-regex: '^([^\s(]+)(?:\(([^)]+)\))?: (.+)'
+ pr-title-regex: '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\([^)]+\))?!?: .+'
diff --git a/.github/workflows/create-backport-label.yml b/.github/workflows/create-backport-label.yml
index 3b485ec513..b4308156c7 100644
--- a/.github/workflows/create-backport-label.yml
+++ b/.github/workflows/create-backport-label.yml
@@ -1,67 +1,70 @@
-name: Prowler - Create Backport Label
+name: 'Tools: Backport Label'
on:
release:
- types: [published]
+ types:
+ - 'published'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
+ cancel-in-progress: false
+
+env:
+ BACKPORT_LABEL_PREFIX: backport-to-
+ BACKPORT_LABEL_COLOR: B60205
jobs:
- create_label:
+ create-label:
runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
- contents: write
+ contents: read
issues: write
+
steps:
- - name: Create backport label
+ - name: Create backport label for minor releases
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- RELEASE_TAG: ${{ github.event.release.tag_name }}
- OWNER_REPO: ${{ github.repository }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- VERSION_ONLY=${RELEASE_TAG#v} # Remove 'v' prefix if present (e.g., v3.2.0 -> 3.2.0)
+ RELEASE_TAG="${{ github.event.release.tag_name }}"
+
+ if [ -z "$RELEASE_TAG" ]; then
+ echo "Error: No release tag provided"
+ exit 1
+ fi
+
+ echo "Processing release tag: $RELEASE_TAG"
+
+ # Remove 'v' prefix if present (e.g., v3.2.0 -> 3.2.0)
+ VERSION_ONLY="${RELEASE_TAG#v}"
# Check if it's a minor version (X.Y.0)
- if [[ "$VERSION_ONLY" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then
- echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is a minor version. Proceeding to create backport label."
+ if [[ "$VERSION_ONLY" =~ ^([0-9]+)\.([0-9]+)\.0$ ]]; then
+ echo "Release $RELEASE_TAG (version $VERSION_ONLY) is a minor version. Proceeding to create backport label."
- TWO_DIGIT_VERSION=${VERSION_ONLY%.0} # Extract X.Y from X.Y.0 (e.g., 5.6 from 5.6.0)
+ # Extract X.Y from X.Y.0 (e.g., 5.6 from 5.6.0)
+ MAJOR="${BASH_REMATCH[1]}"
+ MINOR="${BASH_REMATCH[2]}"
+ TWO_DIGIT_VERSION="${MAJOR}.${MINOR}"
- FINAL_LABEL_NAME="backport-to-v${TWO_DIGIT_VERSION}"
- FINAL_DESCRIPTION="Backport PR to the v${TWO_DIGIT_VERSION} branch"
+ LABEL_NAME="${BACKPORT_LABEL_PREFIX}v${TWO_DIGIT_VERSION}"
+ LABEL_DESC="Backport PR to the v${TWO_DIGIT_VERSION} branch"
+ LABEL_COLOR="$BACKPORT_LABEL_COLOR"
- echo "Effective label name will be: ${FINAL_LABEL_NAME}"
- echo "Effective description will be: ${FINAL_DESCRIPTION}"
+ echo "Label name: $LABEL_NAME"
+ echo "Label description: $LABEL_DESC"
- # Check if the label already exists
- STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${GITHUB_TOKEN}" "https://api.github.com/repos/${OWNER_REPO}/labels/${FINAL_LABEL_NAME}")
-
- if [ "${STATUS_CODE}" -eq 200 ]; then
- echo "Label '${FINAL_LABEL_NAME}' already exists."
- elif [ "${STATUS_CODE}" -eq 404 ]; then
- echo "Label '${FINAL_LABEL_NAME}' does not exist. Creating it..."
- # Prepare JSON data payload
- JSON_DATA=$(printf '{"name":"%s","description":"%s","color":"B60205"}' "${FINAL_LABEL_NAME}" "${FINAL_DESCRIPTION}")
-
- CREATE_STATUS_CODE=$(curl -s -o /tmp/curl_create_response.json -w "%{http_code}" -X POST \
- -H "Accept: application/vnd.github.v3+json" \
- -H "Authorization: token ${GITHUB_TOKEN}" \
- --data "${JSON_DATA}" \
- "https://api.github.com/repos/${OWNER_REPO}/labels")
-
- CREATE_RESPONSE_BODY=$(cat /tmp/curl_create_response.json)
- rm -f /tmp/curl_create_response.json
-
- if [ "$CREATE_STATUS_CODE" -eq 201 ]; then
- echo "Label '${FINAL_LABEL_NAME}' created successfully."
- else
- echo "Error creating label '${FINAL_LABEL_NAME}'. Status: $CREATE_STATUS_CODE"
- echo "Response: $CREATE_RESPONSE_BODY"
- exit 1
- fi
+ # Check if label already exists
+ if gh label list --repo ${{ github.repository }} --limit 1000 | grep -q "^${LABEL_NAME}[[:space:]]"; then
+ echo "Label '$LABEL_NAME' already exists."
else
- echo "Error checking for label '${FINAL_LABEL_NAME}'. HTTP Status: ${STATUS_CODE}"
- exit 1
+ echo "Label '$LABEL_NAME' does not exist. Creating it..."
+ gh label create "$LABEL_NAME" \
+ --description "$LABEL_DESC" \
+ --color "$LABEL_COLOR" \
+ --repo ${{ github.repository }}
+ echo "Label '$LABEL_NAME' created successfully."
fi
else
- echo "Release ${RELEASE_TAG} (version ${VERSION_ONLY}) is not a minor version. Skipping backport label creation."
- exit 0
+ echo "Release $RELEASE_TAG (version $VERSION_ONLY) is not a minor version. Skipping backport label creation."
fi
diff --git a/.github/workflows/find-secrets.yml b/.github/workflows/find-secrets.yml
index 8160c7028a..80b49e3279 100644
--- a/.github/workflows/find-secrets.yml
+++ b/.github/workflows/find-secrets.yml
@@ -1,19 +1,33 @@
-name: Prowler - Find secrets
+name: 'Tools: TruffleHog'
-on: pull_request
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
- trufflehog:
+ scan-secrets:
runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+
steps:
- - name: Checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- - name: TruffleHog OSS
- uses: trufflesecurity/trufflehog@a05cf0859455b5b16317ee22d809887a4043cdf0 # v3.90.2
+
+ - name: Scan for secrets with TruffleHog
+ uses: trufflesecurity/trufflehog@b84c3d14d189e16da175e2c27fa8136603783ffc # v3.90.12
with:
- path: ./
- base: ${{ github.event.repository.default_branch }}
- head: HEAD
- extra_args: --only-verified
+ extra_args: '--results=verified,unknown'
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 6507474ec8..85ccd34cc2 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -1,17 +1,92 @@
-name: Prowler - PR Labeler
+name: 'Tools: PR Labeler'
on:
- pull_request_target:
- branches:
- - "master"
- - "v3"
- - "v4.*"
+ pull_request_target:
+ branches:
+ - 'master'
+ - 'v5.*'
+ types:
+ - 'opened'
+ - 'reopened'
+ - 'synchronize'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
jobs:
labeler:
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
contents: read
pull-requests: write
- runs-on: ubuntu-latest
+
steps:
- - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
+ - name: Apply labels to PR
+ uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
+ with:
+ sync-labels: true
+
+ label-community:
+ name: Add 'community' label if the PR is from a community contributor
+ needs: labeler
+ if: github.repository == 'prowler-cloud/prowler' && github.event.action == 'opened'
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+
+ steps:
+ - name: Check if author is org member
+ id: check_membership
+ env:
+ AUTHOR: ${{ github.event.pull_request.user.login }}
+ run: |
+ # Hardcoded list of prowler-cloud organization members
+ # This list includes members who have set their organization membership as private
+ ORG_MEMBERS=(
+ "AdriiiPRodri"
+ "Alan-TheGentleman"
+ "alejandrobailo"
+ "amitsharm"
+ "andoniaf"
+ "cesararroba"
+ "Chan9390"
+ "danibarranqueroo"
+ "HugoPBrito"
+ "jfagoagas"
+ "josemazo"
+ "lydiavilchez"
+ "mmuller88"
+ "MrCloudSec"
+ "pedrooot"
+ "prowler-bot"
+ "puchy22"
+ "rakan-pro"
+ "RosaRivasProwler"
+ "StylusFrost"
+ "toniblyx"
+ "vicferpoy"
+ )
+
+ echo "Checking if $AUTHOR is a member of prowler-cloud organization"
+
+ # Check if author is in the org members list
+ if printf '%s\n' "${ORG_MEMBERS[@]}" | grep -q "^${AUTHOR}$"; then
+ echo "is_member=true" >> $GITHUB_OUTPUT
+ echo "$AUTHOR is an organization member"
+ else
+ echo "is_member=false" >> $GITHUB_OUTPUT
+ echo "$AUTHOR is not an organization member"
+ fi
+
+ - name: Add community label
+ if: steps.check_membership.outputs.is_member == 'false'
+ env:
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ echo "Adding 'community' label to PR #$PR_NUMBER"
+ gh api /repos/${{ github.repository }}/issues/${{ github.event.number }}/labels \
+ -X POST \
+ -f labels[]='community'
diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml
new file mode 100644
index 0000000000..27bc3e84e0
--- /dev/null
+++ b/.github/workflows/mcp-container-build-push.yml
@@ -0,0 +1,183 @@
+name: 'MCP: Container Build and Push'
+
+on:
+ push:
+ branches:
+ - 'master'
+ paths:
+ - 'mcp_server/**'
+ - '.github/workflows/mcp-container-build-push.yml'
+ release:
+ types:
+ - 'published'
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ # Tags
+ LATEST_TAG: latest
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
+ STABLE_TAG: stable
+ WORKING_DIRECTORY: ./mcp_server
+
+ # Container registries
+ PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
+ PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-mcp
+
+jobs:
+ setup:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ outputs:
+ short-sha: ${{ steps.set-short-sha.outputs.short-sha }}
+ steps:
+ - name: Calculate short SHA
+ id: set-short-sha
+ run: echo "short-sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
+
+ container-build-push:
+ needs: setup
+ runs-on: ${{ matrix.runner }}
+ strategy:
+ matrix:
+ include:
+ - platform: linux/amd64
+ runner: ubuntu-latest
+ arch: amd64
+ - platform: linux/arm64
+ runner: ubuntu-24.04-arm
+ arch: arm64
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Login to DockerHub
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build and push MCP container for ${{ matrix.arch }}
+ if: github.event_name == 'push' || github.event_name == 'release'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.WORKING_DIRECTORY }}
+ push: true
+ platforms: ${{ matrix.platform }}
+ tags: |
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-${{ matrix.arch }}
+ labels: |
+ org.opencontainers.image.title=Prowler MCP Server
+ org.opencontainers.image.description=Model Context Protocol server for Prowler
+ org.opencontainers.image.vendor=ProwlerPro, Inc.
+ org.opencontainers.image.source=https://github.com/${{ github.repository }}
+ org.opencontainers.image.revision=${{ github.sha }}
+ org.opencontainers.image.created=${{ github.event_name == 'release' && github.event.release.published_at || github.event.head_commit.timestamp }}
+ ${{ github.event_name == 'release' && format('org.opencontainers.image.version={0}', env.RELEASE_TAG) || '' }}
+ cache-from: type=gha,scope=${{ matrix.arch }}
+ cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
+
+ - name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: MCP
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+ - name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: MCP
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+ step-outcome: ${{ steps.container-push.outcome }}
+
+ # Create and push multi-architecture manifest
+ create-manifest:
+ needs: [setup, container-build-push]
+ if: github.event_name == 'push' || github.event_name == 'release'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Login to DockerHub
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Create and push manifests for push event
+ if: github.event_name == 'push'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Create and push manifests for release event
+ if: github.event_name == 'release'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Install regctl
+ if: always()
+ uses: regclient/actions/regctl-installer@main
+
+ - name: Cleanup intermediate architecture tags
+ if: always()
+ run: |
+ echo "Cleaning up intermediate tags..."
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64" || true
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64" || true
+ echo "Cleanup completed"
+
+ trigger-deployment:
+ if: github.event_name == 'push'
+ needs: [setup, container-build-push]
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+
+ steps:
+ - name: Trigger MCP deployment
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ repository: ${{ secrets.CLOUD_DISPATCH }}
+ event-type: mcp-prowler-deployment
+ client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ needs.setup.outputs.short-sha }}"}'
diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml
new file mode 100644
index 0000000000..3310cd8c5a
--- /dev/null
+++ b/.github/workflows/mcp-container-checks.yml
@@ -0,0 +1,87 @@
+name: 'MCP: Container Checks'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ MCP_WORKING_DIR: ./mcp_server
+ IMAGE_NAME: prowler-mcp
+
+jobs:
+ mcp-dockerfile-lint:
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check if Dockerfile changed
+ id: dockerfile-changed
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: mcp_server/Dockerfile
+
+ - name: Lint Dockerfile with Hadolint
+ if: steps.dockerfile-changed.outputs.any_changed == 'true'
+ uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
+ with:
+ dockerfile: mcp_server/Dockerfile
+
+ mcp-container-build-and-scan:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for MCP changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: mcp_server/**
+ files_ignore: |
+ mcp_server/README.md
+ mcp_server/CHANGELOG.md
+
+ - name: Set up Docker Buildx
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build MCP container
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.MCP_WORKING_DIR }}
+ push: false
+ load: true
+ tags: ${{ env.IMAGE_NAME }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Scan MCP container with Trivy
+ if: github.repository == 'prowler-cloud/prowler' && steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/trivy-scan
+ with:
+ image-name: ${{ env.IMAGE_NAME }}
+ image-tag: ${{ github.sha }}
+ fail-on-critical: 'false'
+ severity: 'CRITICAL'
diff --git a/.github/workflows/pr-check-changelog.yml b/.github/workflows/pr-check-changelog.yml
new file mode 100644
index 0000000000..d1a3220402
--- /dev/null
+++ b/.github/workflows/pr-check-changelog.yml
@@ -0,0 +1,103 @@
+name: 'Tools: Check Changelog'
+
+on:
+ pull_request:
+ types:
+ - 'opened'
+ - 'synchronize'
+ - 'reopened'
+ - 'labeled'
+ - 'unlabeled'
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
+jobs:
+ check-changelog:
+ if: contains(github.event.pull_request.labels.*.name, 'no-changelog') == false
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ pull-requests: write
+ env:
+ MONITORED_FOLDERS: 'api ui prowler mcp_server'
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ fetch-depth: 0
+
+ - name: Get changed files
+ id: changed-files
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ api/**
+ ui/**
+ prowler/**
+ mcp_server/**
+
+ - name: Check for folder changes and changelog presence
+ id: check-folders
+ run: |
+ missing_changelogs=""
+
+ # Check api folder
+ if [[ "${{ steps.changed-files.outputs.any_changed }}" == "true" ]]; then
+ for folder in $MONITORED_FOLDERS; do
+ # Get files changed in this folder
+ changed_in_folder=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep "^${folder}/" || true)
+
+ if [ -n "$changed_in_folder" ]; then
+ echo "Detected changes in ${folder}/"
+
+ # Check if CHANGELOG.md was updated
+ if ! echo "$changed_in_folder" | grep -q "^${folder}/CHANGELOG.md$"; then
+ echo "No changelog update found for ${folder}/"
+ missing_changelogs="${missing_changelogs}- \`${folder}\`"$'\n'
+ fi
+ fi
+ done
+ fi
+
+ {
+ echo "missing_changelogs<> $GITHUB_OUTPUT
+
+ - name: Find existing changelog comment
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ id: find-comment
+ uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-author: 'github-actions[bot]'
+ body-includes: ''
+
+ - name: Update PR comment with changelog status
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-id: ${{ steps.find-comment.outputs.comment-id }}
+ edit-mode: replace
+ body: |
+
+ ${{ steps.check-folders.outputs.missing_changelogs != '' && format('ā ļø **Changes detected in the following folders without a corresponding update to the `CHANGELOG.md`:**
+
+ {0}
+
+ Please add an entry to the corresponding `CHANGELOG.md` file to maintain a clear history of changes.', steps.check-folders.outputs.missing_changelogs) || 'ā
All necessary `CHANGELOG.md` files have been updated.' }}
+
+ - name: Fail if changelog is missing
+ if: steps.check-folders.outputs.missing_changelogs != ''
+ run: |
+ echo "::error::Missing changelog updates in some folders"
+ exit 1
diff --git a/.github/workflows/pr-conflict-checker.yml b/.github/workflows/pr-conflict-checker.yml
index 2071dbaa78..c46fafc2d0 100644
--- a/.github/workflows/pr-conflict-checker.yml
+++ b/.github/workflows/pr-conflict-checker.yml
@@ -1,40 +1,40 @@
-name: Prowler - PR Conflict Checker
+name: 'Tools: PR Conflict Checker'
on:
- pull_request:
- types:
- - opened
- - synchronize
- - reopened
- branches:
- - "master"
- - "v5.*"
pull_request_target:
types:
- - opened
- - synchronize
- - reopened
+ - 'opened'
+ - 'synchronize'
+ - 'reopened'
branches:
- - "master"
- - "v5.*"
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
jobs:
- conflict-checker:
+ check-conflicts:
runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
contents: read
pull-requests: write
+ issues: write
steps:
- - name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Checkout PR head
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
- name: Get changed files
id: changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
with:
- files: |
- **
+ files: '**'
- name: Check for conflict markers
id: conflict-check
@@ -49,10 +49,10 @@ jobs:
if [ -f "$file" ]; then
echo "Checking file: $file"
- # Look for conflict markers
- if grep -l "^<<<<<<<\|^=======\|^>>>>>>>" "$file" 2>/dev/null; then
+ # Look for conflict markers (more precise regex)
+ if grep -qE '^(<<<<<<<|=======|>>>>>>>)' "$file" 2>/dev/null; then
echo "Conflict markers found in: $file"
- CONFLICT_FILES="$CONFLICT_FILES$file "
+ CONFLICT_FILES="${CONFLICT_FILES}- \`${file}\`"$'\n'
HAS_CONFLICTS=true
fi
fi
@@ -60,107 +60,64 @@ jobs:
if [ "$HAS_CONFLICTS" = true ]; then
echo "has_conflicts=true" >> $GITHUB_OUTPUT
- echo "conflict_files=$CONFLICT_FILES" >> $GITHUB_OUTPUT
- echo "Conflict markers detected in files: $CONFLICT_FILES"
+ {
+ echo "conflict_files<> $GITHUB_OUTPUT
+ echo "Conflict markers detected"
else
echo "has_conflicts=false" >> $GITHUB_OUTPUT
echo "No conflict markers found in changed files"
fi
- - name: Add conflict label
- if: steps.conflict-check.outputs.has_conflicts == 'true'
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
- with:
- github-token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- script: |
- const { data: labels } = await github.rest.issues.listLabelsOnIssue({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- });
+ - name: Manage conflict label
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ github.event.pull_request.number }}
+ HAS_CONFLICTS: ${{ steps.conflict-check.outputs.has_conflicts }}
+ run: |
+ LABEL_NAME="has-conflicts"
- const hasConflictLabel = labels.some(label => label.name === 'has-conflicts');
+ # Add or remove label based on conflict status
+ if [ "$HAS_CONFLICTS" = "true" ]; then
+ echo "Adding conflict label to PR #${PR_NUMBER}..."
+ gh pr edit "$PR_NUMBER" --add-label "$LABEL_NAME" --repo ${{ github.repository }} || true
+ else
+ echo "Removing conflict label from PR #${PR_NUMBER}..."
+ gh pr edit "$PR_NUMBER" --remove-label "$LABEL_NAME" --repo ${{ github.repository }} || true
+ fi
- if (!hasConflictLabel) {
- await github.rest.issues.addLabels({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- labels: ['has-conflicts']
- });
- console.log('Added has-conflicts label');
- } else {
- console.log('has-conflicts label already exists');
- }
-
- - name: Remove conflict label
- if: steps.conflict-check.outputs.has_conflicts == 'false'
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
- with:
- script: |
- try {
- await github.rest.issues.removeLabel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- name: 'has-conflicts'
- });
- console.log('Removed has-conflicts label');
- } catch (error) {
- if (error.status === 404) {
- console.log('has-conflicts label was not present');
- } else {
- throw error;
- }
- }
-
- - name: Find existing conflict comment
- if: steps.conflict-check.outputs.has_conflicts == 'true'
- uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
+ - name: Find existing comment
+ uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
- body-regex: '(ā ļø \*\*Conflict Markers Detected\*\*|ā
\*\*Conflict Markers Resolved\*\*)'
+ body-includes: ''
- - name: Create or update conflict comment
- if: steps.conflict-check.outputs.has_conflicts == 'true'
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
+ - name: Create or update comment
+ uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
edit-mode: replace
body: |
- ā ļø **Conflict Markers Detected**
+
+ ${{ steps.conflict-check.outputs.has_conflicts == 'true' && 'ā ļø **Conflict Markers Detected**' || 'ā
**Conflict Markers Resolved**' }}
- This pull request contains unresolved conflict markers in the following files:
- ```
- ${{ steps.conflict-check.outputs.conflict_files }}
- ```
+ ${{ steps.conflict-check.outputs.has_conflicts == 'true' && format('This pull request contains unresolved conflict markers in the following files:
+
+ {0}
Please resolve these conflicts by:
1. Locating the conflict markers: `<<<<<<<`, `=======`, and `>>>>>>>`
2. Manually editing the files to resolve the conflicts
3. Removing all conflict markers
- 4. Committing and pushing the changes
+ 4. Committing and pushing the changes', steps.conflict-check.outputs.conflict_files) || 'All conflict markers have been successfully resolved in this pull request.' }}
- - name: Find existing conflict comment when resolved
- if: steps.conflict-check.outputs.has_conflicts == 'false'
- uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
- id: find-resolved-comment
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- body-regex: '(ā ļø \*\*Conflict Markers Detected\*\*|ā
\*\*Conflict Markers Resolved\*\*)'
-
- - name: Update comment when conflicts resolved
- if: steps.conflict-check.outputs.has_conflicts == 'false' && steps.find-resolved-comment.outputs.comment-id != ''
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
- with:
- comment-id: ${{ steps.find-resolved-comment.outputs.comment-id }}
- issue-number: ${{ github.event.pull_request.number }}
- edit-mode: replace
- body: |
- ā
**Conflict Markers Resolved**
-
- All conflict markers have been successfully resolved in this pull request.
+ - name: Fail workflow if conflicts detected
+ if: steps.conflict-check.outputs.has_conflicts == 'true'
+ run: |
+ echo "::error::Workflow failed due to conflict markers detected in the PR"
+ exit 1
diff --git a/.github/workflows/pull-request-merged.yml b/.github/workflows/pr-merged.yml
similarity index 50%
rename from .github/workflows/pull-request-merged.yml
rename to .github/workflows/pr-merged.yml
index 8f6f73a379..d8255026e6 100644
--- a/.github/workflows/pull-request-merged.yml
+++ b/.github/workflows/pr-merged.yml
@@ -1,28 +1,32 @@
-name: Prowler - Merged Pull Request
+name: 'Tools: PR Merged'
on:
pull_request_target:
- branches: ['master']
- types: ['closed']
+ branches:
+ - 'master'
+ types:
+ - 'closed'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: false
jobs:
trigger-cloud-pull-request:
- name: Trigger Cloud Pull Request
if: github.event.pull_request.merged == true && github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
+ timeout-minutes: 10
+ permissions:
+ contents: read
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- ref: ${{ github.event.pull_request.merge_commit_sha }}
-
- - name: Set short git commit SHA
+ - name: Calculate short commit SHA
id: vars
run: |
- shortSha=$(git rev-parse --short ${{ github.event.pull_request.merge_commit_sha }})
- echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
+ SHORT_SHA="${{ github.event.pull_request.merge_commit_sha }}"
+ echo "SHORT_SHA=${SHORT_SHA::7}" >> $GITHUB_ENV
- - name: Trigger pull request
- uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
+ - name: Trigger Cloud repository pull request
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
with:
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
repository: ${{ secrets.CLOUD_DISPATCH }}
@@ -31,8 +35,12 @@ jobs:
{
"PROWLER_COMMIT_SHA": "${{ github.event.pull_request.merge_commit_sha }}",
"PROWLER_COMMIT_SHORT_SHA": "${{ env.SHORT_SHA }}",
+ "PROWLER_PR_NUMBER": "${{ github.event.pull_request.number }}",
"PROWLER_PR_TITLE": ${{ toJson(github.event.pull_request.title) }},
"PROWLER_PR_LABELS": ${{ toJson(github.event.pull_request.labels.*.name) }},
"PROWLER_PR_BODY": ${{ toJson(github.event.pull_request.body) }},
- "PROWLER_PR_URL": ${{ toJson(github.event.pull_request.html_url) }}
+ "PROWLER_PR_URL": ${{ toJson(github.event.pull_request.html_url) }},
+ "PROWLER_PR_MERGED_BY": "${{ github.event.pull_request.merged_by.login }}",
+ "PROWLER_PR_BASE_BRANCH": "${{ github.event.pull_request.base.ref }}",
+ "PROWLER_PR_HEAD_BRANCH": "${{ github.event.pull_request.head.ref }}"
}
diff --git a/.github/workflows/prowler-release-preparation.yml b/.github/workflows/prepare-release.yml
similarity index 51%
rename from .github/workflows/prowler-release-preparation.yml
rename to .github/workflows/prepare-release.yml
index 6008a25795..ae039bd5a6 100644
--- a/.github/workflows/prowler-release-preparation.yml
+++ b/.github/workflows/prepare-release.yml
@@ -1,6 +1,6 @@
-name: Prowler - Release Preparation
+name: 'Tools: Prepare Release'
-run-name: Prowler Release Preparation for ${{ inputs.prowler_version }}
+run-name: 'Prepare Release for Prowler ${{ inputs.prowler_version }}'
on:
workflow_dispatch:
@@ -10,37 +10,42 @@ on:
required: true
type: string
+concurrency:
+ group: ${{ github.workflow }}-${{ inputs.prowler_version }}
+ cancel-in-progress: false
+
env:
- PROWLER_VERSION: ${{ github.event.inputs.prowler_version }}
+ PROWLER_VERSION: ${{ inputs.prowler_version }}
jobs:
prepare-release:
- if: github.repository == 'prowler-cloud/prowler'
+ if: github.event_name == 'workflow_dispatch' && github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
+ timeout-minutes: 30
permissions:
contents: write
pull-requests: write
steps:
- - name: Checkout code
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- name: Set up Python
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: '3.12'
- name: Install Poetry
run: |
- python3 -m pip install --user poetry
+ python3 -m pip install --user poetry==2.1.1
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Configure Git
run: |
- git config --global user.name "prowler-bot"
- git config --global user.email "179230569+prowler-bot@users.noreply.github.com"
+ git config --global user.name 'prowler-bot'
+ git config --global user.email '179230569+prowler-bot@users.noreply.github.com'
- name: Parse version and determine branch
run: |
@@ -59,29 +64,17 @@ jobs:
BRANCH_NAME="v${MAJOR_VERSION}.${MINOR_VERSION}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_ENV}"
- # Calculate UI version (1.X.X format - matches Prowler minor version)
- UI_VERSION="1.${MINOR_VERSION}.${PATCH_VERSION}"
- echo "UI_VERSION=${UI_VERSION}" >> "${GITHUB_ENV}"
-
- # Calculate API version (1.X.X format - one minor version ahead)
- API_MINOR_VERSION=$((MINOR_VERSION + 1))
- API_VERSION="1.${API_MINOR_VERSION}.${PATCH_VERSION}"
- echo "API_VERSION=${API_VERSION}" >> "${GITHUB_ENV}"
-
echo "Prowler version: $PROWLER_VERSION"
echo "Branch name: $BRANCH_NAME"
- echo "UI version: $UI_VERSION"
- echo "API version: $API_VERSION"
echo "Is minor release: $([ $PATCH_VERSION -eq 0 ] && echo 'true' || echo 'false')"
else
echo "Invalid version syntax: '$PROWLER_VERSION' (must be N.N.N)" >&2
exit 1
fi
- - name: Checkout existing branch for patch release
- if: ${{ env.PATCH_VERSION != '0' }}
+ - name: Checkout release branch
run: |
- echo "Patch release detected, checking out existing branch $BRANCH_NAME..."
+ echo "Checking out branch $BRANCH_NAME for release $PROWLER_VERSION..."
if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then
echo "Branch $BRANCH_NAME exists locally, checking out..."
git checkout "$BRANCH_NAME"
@@ -89,139 +82,66 @@ jobs:
echo "Branch $BRANCH_NAME exists remotely, checking out..."
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
else
- echo "ERROR: Branch $BRANCH_NAME should exist for patch release $PROWLER_VERSION"
+ echo "ERROR: Branch $BRANCH_NAME does not exist. For minor releases (X.Y.0), create it manually first. For patch releases (X.Y.Z), the branch should already exist."
exit 1
fi
- - name: Verify version in pyproject.toml
+ - name: Read changelog versions from release branch
run: |
- CURRENT_VERSION=$(grep '^version = ' pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
- PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
- if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
- echo "ERROR: Version mismatch in pyproject.toml (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
- exit 1
- fi
- echo "ā pyproject.toml version: $CURRENT_VERSION"
+ # Function to extract the latest version from changelog
+ extract_latest_version() {
+ local changelog_file="$1"
+ if [ -f "$changelog_file" ]; then
+ # Extract the first version entry (most recent) from changelog
+ # Format: ## [version] (1.2.3) or ## [vversion] (v1.2.3)
+ local version=$(grep -m 1 '^## \[' "$changelog_file" | sed 's/^## \[\(.*\)\].*/\1/' | sed 's/^v//' | tr -d '[:space:]')
+ echo "$version"
+ else
+ echo ""
+ fi
+ }
- - name: Verify version in prowler/config/config.py
- run: |
- CURRENT_VERSION=$(grep '^prowler_version = ' prowler/config/config.py | sed -E 's/prowler_version = "([^"]+)"/\1/' | tr -d '[:space:]')
- PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
- if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
- echo "ERROR: Version mismatch in prowler/config/config.py (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
- exit 1
- fi
- echo "ā prowler/config/config.py version: $CURRENT_VERSION"
+ # Read actual versions from changelogs (source of truth)
+ UI_VERSION=$(extract_latest_version "ui/CHANGELOG.md")
+ API_VERSION=$(extract_latest_version "api/CHANGELOG.md")
+ SDK_VERSION=$(extract_latest_version "prowler/CHANGELOG.md")
+ MCP_VERSION=$(extract_latest_version "mcp_server/CHANGELOG.md")
- - name: Verify version in api/pyproject.toml
- run: |
- CURRENT_API_VERSION=$(grep '^version = ' api/pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
- API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
- if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
- echo "ERROR: API version mismatch in api/pyproject.toml (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
- exit 1
- fi
- echo "ā api/pyproject.toml version: $CURRENT_API_VERSION"
+ echo "UI_VERSION=${UI_VERSION}" >> "${GITHUB_ENV}"
+ echo "API_VERSION=${API_VERSION}" >> "${GITHUB_ENV}"
+ echo "SDK_VERSION=${SDK_VERSION}" >> "${GITHUB_ENV}"
+ echo "MCP_VERSION=${MCP_VERSION}" >> "${GITHUB_ENV}"
- - name: Verify prowler dependency in api/pyproject.toml
- if: ${{ env.PATCH_VERSION != '0' }}
- run: |
- CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
- BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
- if [ "$CURRENT_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
- echo "ERROR: Prowler dependency mismatch in api/pyproject.toml (expected: '$BRANCH_NAME_TRIMMED', found: '$CURRENT_PROWLER_REF')"
- exit 1
- fi
- echo "ā api/pyproject.toml prowler dependency: $CURRENT_PROWLER_REF"
-
- - name: Verify version in api/src/backend/api/v1/views.py
- run: |
- CURRENT_API_VERSION=$(grep 'spectacular_settings.VERSION = ' api/src/backend/api/v1/views.py | sed -E 's/.*spectacular_settings.VERSION = "([^"]+)".*/\1/' | tr -d '[:space:]')
- API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
- if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
- echo "ERROR: API version mismatch in views.py (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
- exit 1
- fi
- echo "ā api/src/backend/api/v1/views.py version: $CURRENT_API_VERSION"
-
- - name: Checkout existing release branch for minor release
- if: ${{ env.PATCH_VERSION == '0' }}
- run: |
- echo "Minor release detected (patch = 0), checking out existing branch $BRANCH_NAME..."
- if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH_NAME"; then
- echo "Branch $BRANCH_NAME exists remotely, checking out..."
- git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
+ if [ -n "$UI_VERSION" ]; then
+ echo "Read UI version from changelog: $UI_VERSION"
else
- echo "ERROR: Branch $BRANCH_NAME should exist for minor release $PROWLER_VERSION. Please create it manually first."
- exit 1
+ echo "Warning: No UI version found in ui/CHANGELOG.md"
fi
- - name: Prepare prowler dependency update for minor release
- if: ${{ env.PATCH_VERSION == '0' }}
- run: |
- CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
- BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
-
- # Create a temporary branch for the PR
- TEMP_BRANCH="update-api-dependency-$BRANCH_NAME_TRIMMED-$(date +%s)"
- echo "TEMP_BRANCH=$TEMP_BRANCH" >> $GITHUB_ENV
-
- # Switch back to master and create temp branch
- git checkout master
- git checkout -b "$TEMP_BRANCH"
-
- # Minor release: update the dependency to use the release branch
- echo "Updating prowler dependency from '$CURRENT_PROWLER_REF' to '$BRANCH_NAME_TRIMMED'"
- sed -i "s|prowler @ git+https://github.com/prowler-cloud/prowler.git@[^\"]*\"|prowler @ git+https://github.com/prowler-cloud/prowler.git@$BRANCH_NAME_TRIMMED\"|" api/pyproject.toml
-
- # Verify the change was made
- UPDATED_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
- if [ "$UPDATED_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
- echo "ERROR: Failed to update prowler dependency in api/pyproject.toml"
- exit 1
+ if [ -n "$API_VERSION" ]; then
+ echo "Read API version from changelog: $API_VERSION"
+ else
+ echo "Warning: No API version found in api/CHANGELOG.md"
fi
- # Update poetry lock file
- echo "Updating poetry.lock file..."
- cd api
- poetry lock
- cd ..
+ if [ -n "$SDK_VERSION" ]; then
+ echo "Read SDK version from changelog: $SDK_VERSION"
+ else
+ echo "Warning: No SDK version found in prowler/CHANGELOG.md"
+ fi
- # Commit and push the temporary branch
- git add api/pyproject.toml api/poetry.lock
- git commit -m "chore(api): update prowler dependency to $BRANCH_NAME_TRIMMED for release $PROWLER_VERSION"
- git push origin "$TEMP_BRANCH"
+ if [ -n "$MCP_VERSION" ]; then
+ echo "Read MCP version from changelog: $MCP_VERSION"
+ else
+ echo "Warning: No MCP version found in mcp_server/CHANGELOG.md"
+ fi
- echo "ā Prepared prowler dependency update to: $UPDATED_PROWLER_REF"
+ echo "UI version: $UI_VERSION"
+ echo "API version: $API_VERSION"
+ echo "SDK version: $SDK_VERSION"
+ echo "MCP version: $MCP_VERSION"
- - name: Create Pull Request against release branch
- if: ${{ env.PATCH_VERSION == '0' }}
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
- with:
- token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- branch: ${{ env.TEMP_BRANCH }}
- base: ${{ env.BRANCH_NAME }}
- title: "chore(api): Update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}"
- body: |
- ### Description
-
- Updates the API prowler dependency for release ${{ env.PROWLER_VERSION }}.
-
- **Changes:**
- - Updates `api/pyproject.toml` prowler dependency from `@master` to `@${{ env.BRANCH_NAME }}`
- - Updates `api/poetry.lock` file with resolved dependencies
-
- This PR should be merged into the `${{ env.BRANCH_NAME }}` release branch.
-
- ### License
-
- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
- author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
- labels: |
- component/api
- no-changelog
-
- - name: Extract changelog entries
+ - name: Extract and combine changelog entries
run: |
set -e
@@ -247,54 +167,232 @@ jobs:
# Remove --- separators
sed -i '/^---$/d' "$output_file"
- # Remove trailing empty lines
- sed -i '/^$/d' "$output_file"
+ # Remove only trailing empty lines (not all empty lines)
+ sed -i -e :a -e '/^\s*$/d;N;ba' "$output_file"
}
- # Extract changelogs
- echo "Extracting changelog entries..."
- extract_changelog "prowler/CHANGELOG.md" "$PROWLER_VERSION" "prowler_changelog.md"
- extract_changelog "api/CHANGELOG.md" "$API_VERSION" "api_changelog.md"
- extract_changelog "ui/CHANGELOG.md" "$UI_VERSION" "ui_changelog.md"
+ # Calculate expected versions for this release
+ if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
+ EXPECTED_UI_VERSION="1.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
+ EXPECTED_API_VERSION="1.$((${BASH_REMATCH[2]} + 1)).${BASH_REMATCH[3]}"
- # Combine changelogs in order: UI, API, SDK
+ echo "Expected UI version for this release: $EXPECTED_UI_VERSION"
+ echo "Expected API version for this release: $EXPECTED_API_VERSION"
+ fi
+
+ # Determine if components have changes for this specific release
+ # UI has changes if its current version matches what we expect for this release
+ if [ -n "$UI_VERSION" ] && [ "$UI_VERSION" = "$EXPECTED_UI_VERSION" ]; then
+ echo "HAS_UI_CHANGES=true" >> $GITHUB_ENV
+ echo "ā UI changes detected - version matches expected: $UI_VERSION"
+ extract_changelog "ui/CHANGELOG.md" "$UI_VERSION" "ui_changelog.md"
+ else
+ echo "HAS_UI_CHANGES=false" >> $GITHUB_ENV
+ echo "ā¹ No UI changes for this release (current: $UI_VERSION, expected: $EXPECTED_UI_VERSION)"
+ touch "ui_changelog.md"
+ fi
+
+ # API has changes if its current version matches what we expect for this release
+ if [ -n "$API_VERSION" ] && [ "$API_VERSION" = "$EXPECTED_API_VERSION" ]; then
+ echo "HAS_API_CHANGES=true" >> $GITHUB_ENV
+ echo "ā API changes detected - version matches expected: $API_VERSION"
+ extract_changelog "api/CHANGELOG.md" "$API_VERSION" "api_changelog.md"
+ else
+ echo "HAS_API_CHANGES=false" >> $GITHUB_ENV
+ echo "ā¹ No API changes for this release (current: $API_VERSION, expected: $EXPECTED_API_VERSION)"
+ touch "api_changelog.md"
+ fi
+
+ # SDK has changes if its current version matches the input version
+ if [ -n "$SDK_VERSION" ] && [ "$SDK_VERSION" = "$PROWLER_VERSION" ]; then
+ echo "HAS_SDK_CHANGES=true" >> $GITHUB_ENV
+ echo "ā SDK changes detected - version matches input: $SDK_VERSION"
+ extract_changelog "prowler/CHANGELOG.md" "$PROWLER_VERSION" "prowler_changelog.md"
+ else
+ echo "HAS_SDK_CHANGES=false" >> $GITHUB_ENV
+ echo "ā¹ No SDK changes for this release (current: $SDK_VERSION, input: $PROWLER_VERSION)"
+ touch "prowler_changelog.md"
+ fi
+
+ # MCP has changes if the changelog references this Prowler version
+ # Check if the changelog contains "(Prowler X.Y.Z)" or "(Prowler UNRELEASED)"
+ if [ -f "mcp_server/CHANGELOG.md" ]; then
+ MCP_PROWLER_REF=$(grep -m 1 "^## \[.*\] (Prowler" mcp_server/CHANGELOG.md | sed -E 's/.*\(Prowler ([^)]+)\).*/\1/' | tr -d '[:space:]')
+ if [ "$MCP_PROWLER_REF" = "$PROWLER_VERSION" ] || [ "$MCP_PROWLER_REF" = "UNRELEASED" ]; then
+ echo "HAS_MCP_CHANGES=true" >> $GITHUB_ENV
+ echo "ā MCP changes detected - Prowler reference: $MCP_PROWLER_REF (version: $MCP_VERSION)"
+ extract_changelog "mcp_server/CHANGELOG.md" "$MCP_VERSION" "mcp_changelog.md"
+ else
+ echo "HAS_MCP_CHANGES=false" >> $GITHUB_ENV
+ echo "ā¹ No MCP changes for this release (Prowler reference: $MCP_PROWLER_REF, input: $PROWLER_VERSION)"
+ touch "mcp_changelog.md"
+ fi
+ else
+ echo "HAS_MCP_CHANGES=false" >> $GITHUB_ENV
+ echo "ā¹ No MCP changelog found"
+ touch "mcp_changelog.md"
+ fi
+
+ # Combine changelogs in order: UI, API, SDK, MCP
> combined_changelog.md
- if [ -s "ui_changelog.md" ]; then
+ if [ "$HAS_UI_CHANGES" = "true" ] && [ -s "ui_changelog.md" ]; then
echo "## UI" >> combined_changelog.md
echo "" >> combined_changelog.md
cat ui_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
- if [ -s "api_changelog.md" ]; then
+ if [ "$HAS_API_CHANGES" = "true" ] && [ -s "api_changelog.md" ]; then
echo "## API" >> combined_changelog.md
echo "" >> combined_changelog.md
cat api_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
- if [ -s "prowler_changelog.md" ]; then
+ if [ "$HAS_SDK_CHANGES" = "true" ] && [ -s "prowler_changelog.md" ]; then
echo "## SDK" >> combined_changelog.md
echo "" >> combined_changelog.md
cat prowler_changelog.md >> combined_changelog.md
echo "" >> combined_changelog.md
fi
+ if [ "$HAS_MCP_CHANGES" = "true" ] && [ -s "mcp_changelog.md" ]; then
+ echo "## MCP" >> combined_changelog.md
+ echo "" >> combined_changelog.md
+ cat mcp_changelog.md >> combined_changelog.md
+ echo "" >> combined_changelog.md
+ fi
+
+ # Add fallback message if no changelogs were added
+ if [ ! -s combined_changelog.md ]; then
+ echo "No component changes detected for this release." >> combined_changelog.md
+ fi
+
echo "Combined changelog preview:"
cat combined_changelog.md
+ - name: Verify SDK version in pyproject.toml
+ run: |
+ CURRENT_VERSION=$(grep '^version = ' pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
+ PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
+ if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
+ echo "ERROR: Version mismatch in pyproject.toml (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
+ exit 1
+ fi
+ echo "ā pyproject.toml version: $CURRENT_VERSION"
+
+ - name: Verify SDK version in prowler/config/config.py
+ run: |
+ CURRENT_VERSION=$(grep '^prowler_version = ' prowler/config/config.py | sed -E 's/prowler_version = "([^"]+)"/\1/' | tr -d '[:space:]')
+ PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]')
+ if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then
+ echo "ERROR: Version mismatch in prowler/config/config.py (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')"
+ exit 1
+ fi
+ echo "ā prowler/config/config.py version: $CURRENT_VERSION"
+
+ - name: Verify API version in api/pyproject.toml
+ if: ${{ env.HAS_API_CHANGES == 'true' }}
+ run: |
+ CURRENT_API_VERSION=$(grep '^version = ' api/pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]')
+ API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
+ if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
+ echo "ERROR: API version mismatch in api/pyproject.toml (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
+ exit 1
+ fi
+ echo "ā api/pyproject.toml version: $CURRENT_API_VERSION"
+
+ - name: Verify API prowler dependency in api/pyproject.toml
+ if: ${{ env.PATCH_VERSION != '0' && env.HAS_API_CHANGES == 'true' }}
+ run: |
+ CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
+ BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
+ if [ "$CURRENT_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
+ echo "ERROR: Prowler dependency mismatch in api/pyproject.toml (expected: '$BRANCH_NAME_TRIMMED', found: '$CURRENT_PROWLER_REF')"
+ exit 1
+ fi
+ echo "ā api/pyproject.toml prowler dependency: $CURRENT_PROWLER_REF"
+
+ - name: Verify API version in api/src/backend/api/v1/views.py
+ if: ${{ env.HAS_API_CHANGES == 'true' }}
+ run: |
+ CURRENT_API_VERSION=$(grep 'spectacular_settings.VERSION = ' api/src/backend/api/v1/views.py | sed -E 's/.*spectacular_settings.VERSION = "([^"]+)".*/\1/' | tr -d '[:space:]')
+ API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]')
+ if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then
+ echo "ERROR: API version mismatch in views.py (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')"
+ exit 1
+ fi
+ echo "ā api/src/backend/api/v1/views.py version: $CURRENT_API_VERSION"
+
+ - name: Update API prowler dependency for minor release
+ if: ${{ env.PATCH_VERSION == '0' }}
+ run: |
+ CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
+ BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]')
+
+ # Minor release: update the dependency to use the release branch
+ echo "Updating prowler dependency from '$CURRENT_PROWLER_REF' to '$BRANCH_NAME_TRIMMED'"
+ sed -i "s|prowler @ git+https://github.com/prowler-cloud/prowler.git@[^\"]*\"|prowler @ git+https://github.com/prowler-cloud/prowler.git@$BRANCH_NAME_TRIMMED\"|" api/pyproject.toml
+
+ # Verify the change was made
+ UPDATED_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]')
+ if [ "$UPDATED_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then
+ echo "ERROR: Failed to update prowler dependency in api/pyproject.toml"
+ exit 1
+ fi
+
+ # Update poetry lock file
+ echo "Updating poetry.lock file..."
+ cd api
+ poetry lock
+ cd ..
+
+ echo "ā Prepared prowler dependency update to: $UPDATED_PROWLER_REF"
+
+ - name: Create PR for API dependency update
+ if: ${{ env.PATCH_VERSION == '0' }}
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ commit-message: 'chore(api): update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}'
+ branch: update-api-dependency-${{ env.BRANCH_NAME }}-${{ github.run_number }}
+ base: ${{ env.BRANCH_NAME }}
+ add-paths: |
+ api/pyproject.toml
+ api/poetry.lock
+ title: "chore(api): Update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}"
+ body: |
+ ### Description
+
+ Updates the API prowler dependency for release ${{ env.PROWLER_VERSION }}.
+
+ **Changes:**
+ - Updates `api/pyproject.toml` prowler dependency from `@master` to `@${{ env.BRANCH_NAME }}`
+ - Updates `api/poetry.lock` file with resolved dependencies
+
+ This PR should be merged into the `${{ env.BRANCH_NAME }}` release branch.
+
+ ### License
+
+ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
+ author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
+ labels: |
+ component/api
+ no-changelog
+
- name: Create draft release
- uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
+ uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
with:
tag_name: ${{ env.PROWLER_VERSION }}
name: Prowler ${{ env.PROWLER_VERSION }}
body_path: combined_changelog.md
draft: true
- target_commitish: ${{ env.PATCH_VERSION == '0' && 'master' || env.BRANCH_NAME }}
+ target_commitish: ${{ env.BRANCH_NAME }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Clean up temporary files
+ if: always()
run: |
- rm -f prowler_changelog.md api_changelog.md ui_changelog.md combined_changelog.md
+ rm -f prowler_changelog.md api_changelog.md ui_changelog.md mcp_changelog.md combined_changelog.md
diff --git a/.github/workflows/pull-request-check-changelog.yml b/.github/workflows/pull-request-check-changelog.yml
deleted file mode 100644
index c4e0fa31c0..0000000000
--- a/.github/workflows/pull-request-check-changelog.yml
+++ /dev/null
@@ -1,77 +0,0 @@
-name: Prowler - Check Changelog
-
-on:
- pull_request:
- types: [opened, synchronize, reopened, labeled, unlabeled]
-
-jobs:
- check-changelog:
- if: contains(github.event.pull_request.labels.*.name, 'no-changelog') == false
- runs-on: ubuntu-latest
- permissions:
- id-token: write
- contents: read
- pull-requests: write
- env:
- MONITORED_FOLDERS: "api ui prowler"
-
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- fetch-depth: 0
-
- - name: Get list of changed files
- id: changed_files
- run: |
- git fetch origin ${{ github.base_ref }}
- git diff --name-only origin/${{ github.base_ref }}...HEAD > changed_files.txt
- cat changed_files.txt
-
- - name: Check for folder changes and changelog presence
- id: check_folders
- run: |
- missing_changelogs=""
-
- for folder in $MONITORED_FOLDERS; do
- if grep -q "^${folder}/" changed_files.txt; then
- echo "Detected changes in ${folder}/"
- if ! grep -q "^${folder}/CHANGELOG.md$" changed_files.txt; then
- echo "No changelog update found for ${folder}/"
- missing_changelogs="${missing_changelogs}- \`${folder}\`\n"
- fi
- fi
- done
-
- echo "missing_changelogs<> $GITHUB_OUTPUT
- echo -e "${missing_changelogs}" >> $GITHUB_OUTPUT
- echo "EOF" >> $GITHUB_OUTPUT
-
- - name: Find existing changelog comment
- if: github.event.pull_request.head.repo.full_name == github.repository
- id: find_comment
- uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e #v3.1.0
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- body-includes: ''
-
- - name: Update PR comment with changelog status
- if: github.event.pull_request.head.repo.full_name == github.repository
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-id: ${{ steps.find_comment.outputs.comment-id }}
- edit-mode: replace
- body: |
-
- ${{ steps.check_folders.outputs.missing_changelogs != '' && format('ā ļø **Changes detected in the following folders without a corresponding update to the `CHANGELOG.md`:**
-
- {0}
-
- Please add an entry to the corresponding `CHANGELOG.md` file to maintain a clear history of changes.', steps.check_folders.outputs.missing_changelogs) || 'ā
All necessary `CHANGELOG.md` files have been updated. Great job! š' }}
-
- - name: Fail if changelog is missing
- if: steps.check_folders.outputs.missing_changelogs != ''
- run: |
- echo "ERROR: Missing changelog updates in some folders."
- exit 1
diff --git a/.github/workflows/sdk-build-lint-push-containers.yml b/.github/workflows/sdk-build-lint-push-containers.yml
deleted file mode 100644
index ec1d71a0cb..0000000000
--- a/.github/workflows/sdk-build-lint-push-containers.yml
+++ /dev/null
@@ -1,186 +0,0 @@
-name: SDK - Build and Push containers
-
-on:
- push:
- branches:
- # For `v3-latest`
- - "v3"
- # For `v4-latest`
- - "v4.6"
- # For `latest`
- - "master"
- paths-ignore:
- - ".github/**"
- - "README.md"
- - "docs/**"
- - "ui/**"
- - "api/**"
-
- release:
- types: [published]
-
-env:
- #Ā AWS Configuration
- AWS_REGION_STG: eu-west-1
- AWS_REGION_PLATFORM: eu-west-1
- AWS_REGION: us-east-1
-
- # Container's configuration
- IMAGE_NAME: prowler
- DOCKERFILE_PATH: ./Dockerfile
-
- # Tags
- LATEST_TAG: latest
- STABLE_TAG: stable
- # The RELEASE_TAG is set during runtime in releases
- RELEASE_TAG: ""
- # The PROWLER_VERSION and PROWLER_VERSION_MAJOR are set during runtime in releases
- PROWLER_VERSION: ""
- PROWLER_VERSION_MAJOR: ""
- # TEMPORARY_TAG: temporary
-
- # Python configuration
- PYTHON_VERSION: 3.12
-
- # Container Registries
- PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
- PROWLERCLOUD_DOCKERHUB_IMAGE: prowler
-
-jobs:
- # Build Prowler OSS container
- container-build-push:
- # needs: dockerfile-linter
- runs-on: ubuntu-latest
- outputs:
- prowler_version_major: ${{ steps.get-prowler-version.outputs.PROWLER_VERSION_MAJOR }}
- prowler_version: ${{ steps.get-prowler-version.outputs.PROWLER_VERSION }}
- env:
- POETRY_VIRTUALENVS_CREATE: "false"
-
- steps:
- - name: Checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Setup Python
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- with:
- python-version: ${{ env.PYTHON_VERSION }}
-
- - name: Install Poetry
- run: |
- pipx install poetry==2.*
- pipx inject poetry poetry-bumpversion
-
- - name: Get Prowler version
- id: get-prowler-version
- run: |
- PROWLER_VERSION="$(poetry version -s 2>/dev/null)"
- echo "PROWLER_VERSION=${PROWLER_VERSION}" >> "${GITHUB_ENV}"
- echo "PROWLER_VERSION=${PROWLER_VERSION}" >> "${GITHUB_OUTPUT}"
-
- # Store prowler version major just for the release
- PROWLER_VERSION_MAJOR="${PROWLER_VERSION%%.*}"
- echo "PROWLER_VERSION_MAJOR=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_ENV}"
- echo "PROWLER_VERSION_MAJOR=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_OUTPUT}"
-
- case ${PROWLER_VERSION_MAJOR} in
- 3)
- echo "LATEST_TAG=v3-latest" >> "${GITHUB_ENV}"
- echo "STABLE_TAG=v3-stable" >> "${GITHUB_ENV}"
- ;;
-
-
- 4)
- echo "LATEST_TAG=v4-latest" >> "${GITHUB_ENV}"
- echo "STABLE_TAG=v4-stable" >> "${GITHUB_ENV}"
- ;;
-
- 5)
- echo "LATEST_TAG=latest" >> "${GITHUB_ENV}"
- echo "STABLE_TAG=stable" >> "${GITHUB_ENV}"
- ;;
-
- *)
- # Fallback if any other version is present
- echo "Releasing another Prowler major version, aborting..."
- exit 1
- ;;
- esac
-
- - name: Login to DockerHub
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Login to Public ECR
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- registry: public.ecr.aws
- username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }}
- password: ${{ secrets.PUBLIC_ECR_AWS_SECRET_ACCESS_KEY }}
- env:
- AWS_REGION: ${{ env.AWS_REGION }}
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
-
- - name: Build and push container image (latest)
- if: github.event_name == 'push'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- push: true
- tags: |
- ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.LATEST_TAG }}
- ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.LATEST_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
- file: ${{ env.DOCKERFILE_PATH }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- - name: Build and push container image (release)
- if: github.event_name == 'release'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- # Use local context to get changes
- # https://github.com/docker/build-push-action#path-context
- context: .
- push: true
- tags: |
- ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.PROWLER_VERSION }}
- ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
- ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.PROWLER_VERSION }}
- ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.PROWLER_VERSION }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
- file: ${{ env.DOCKERFILE_PATH }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- dispatch-action:
- needs: container-build-push
- runs-on: ubuntu-latest
- steps:
- - name: Get latest commit info (latest)
- if: github.event_name == 'push'
- run: |
- LATEST_COMMIT_HASH=$(echo ${{ github.event.after }} | cut -b -7)
- echo "LATEST_COMMIT_HASH=${LATEST_COMMIT_HASH}" >> $GITHUB_ENV
-
- - name: Dispatch event (latest)
- if: github.event_name == 'push' && needs.container-build-push.outputs.prowler_version_major == '3'
- run: |
- curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches \
- -H "Accept: application/vnd.github+json" \
- -H "Authorization: Bearer ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- --data '{"event_type":"dispatch","client_payload":{"version":"v3-latest", "tag": "${{ env.LATEST_COMMIT_HASH }}"}}'
-
- - name: Dispatch event (release)
- if: github.event_name == 'release' && needs.container-build-push.outputs.prowler_version_major == '3'
- run: |
- curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches \
- -H "Accept: application/vnd.github+json" \
- -H "Authorization: Bearer ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- --data '{"event_type":"dispatch","client_payload":{"version":"release", "tag":"${{ needs.container-build-push.outputs.prowler_version }}"}}'
diff --git a/.github/workflows/sdk-bump-version.yml b/.github/workflows/sdk-bump-version.yml
index 5ec3fe8d19..0291502ab6 100644
--- a/.github/workflows/sdk-bump-version.yml
+++ b/.github/workflows/sdk-bump-version.yml
@@ -1,146 +1,218 @@
-name: SDK - Bump Version
+name: 'SDK: Bump Version'
on:
release:
- types: [published]
+ types:
+ - 'published'
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
+ cancel-in-progress: false
env:
PROWLER_VERSION: ${{ github.event.release.tag_name }}
BASE_BRANCH: master
jobs:
- bump-version:
- name: Bump Version
+ detect-release-type:
runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+ outputs:
+ is_minor: ${{ steps.detect.outputs.is_minor }}
+ is_patch: ${{ steps.detect.outputs.is_patch }}
+ major_version: ${{ steps.detect.outputs.major_version }}
+ minor_version: ${{ steps.detect.outputs.minor_version }}
+ patch_version: ${{ steps.detect.outputs.patch_version }}
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Get Prowler version
- shell: bash
+ - name: Detect release type and parse version
+ id: detect
run: |
if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
MAJOR_VERSION=${BASH_REMATCH[1]}
MINOR_VERSION=${BASH_REMATCH[2]}
- FIX_VERSION=${BASH_REMATCH[3]}
+ PATCH_VERSION=${BASH_REMATCH[3]}
- # Export version components to GitHub environment
- echo "MAJOR_VERSION=${MAJOR_VERSION}" >> "${GITHUB_ENV}"
- echo "MINOR_VERSION=${MINOR_VERSION}" >> "${GITHUB_ENV}"
- echo "FIX_VERSION=${FIX_VERSION}" >> "${GITHUB_ENV}"
+ echo "major_version=${MAJOR_VERSION}" >> "${GITHUB_OUTPUT}"
+ echo "minor_version=${MINOR_VERSION}" >> "${GITHUB_OUTPUT}"
+ echo "patch_version=${PATCH_VERSION}" >> "${GITHUB_OUTPUT}"
- if (( MAJOR_VERSION == 5 )); then
- if (( FIX_VERSION == 0 )); then
- echo "Minor Release: $PROWLER_VERSION"
+ if (( MAJOR_VERSION != 5 )); then
+ echo "::error::Releasing another Prowler major version, aborting..."
+ exit 1
+ fi
- # Set up next minor version for master
- BUMP_VERSION_TO=${MAJOR_VERSION}.$((MINOR_VERSION + 1)).${FIX_VERSION}
- echo "BUMP_VERSION_TO=${BUMP_VERSION_TO}" >> "${GITHUB_ENV}"
-
- TARGET_BRANCH=${BASE_BRANCH}
- echo "TARGET_BRANCH=${TARGET_BRANCH}" >> "${GITHUB_ENV}"
-
- # Set up patch version for version branch
- PATCH_VERSION_TO=${MAJOR_VERSION}.${MINOR_VERSION}.1
- echo "PATCH_VERSION_TO=${PATCH_VERSION_TO}" >> "${GITHUB_ENV}"
-
- VERSION_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
- echo "VERSION_BRANCH=${VERSION_BRANCH}" >> "${GITHUB_ENV}"
-
- echo "Bumping to next minor version: ${BUMP_VERSION_TO} in branch ${TARGET_BRANCH}"
- echo "Bumping to next patch version: ${PATCH_VERSION_TO} in branch ${VERSION_BRANCH}"
- else
- echo "Patch Release: $PROWLER_VERSION"
-
- BUMP_VERSION_TO=${MAJOR_VERSION}.${MINOR_VERSION}.$((FIX_VERSION + 1))
- echo "BUMP_VERSION_TO=${BUMP_VERSION_TO}" >> "${GITHUB_ENV}"
-
- TARGET_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
- echo "TARGET_BRANCH=${TARGET_BRANCH}" >> "${GITHUB_ENV}"
-
- echo "Bumping to next patch version: ${BUMP_VERSION_TO} in branch ${TARGET_BRANCH}"
- fi
+ if (( PATCH_VERSION == 0 )); then
+ echo "is_minor=true" >> "${GITHUB_OUTPUT}"
+ echo "is_patch=false" >> "${GITHUB_OUTPUT}"
+ echo "ā Minor release detected: $PROWLER_VERSION"
else
- echo "Releasing another Prowler major version, aborting..."
- exit 1
+ echo "is_minor=false" >> "${GITHUB_OUTPUT}"
+ echo "is_patch=true" >> "${GITHUB_OUTPUT}"
+ echo "ā Patch release detected: $PROWLER_VERSION"
fi
else
- echo "Invalid version syntax: '$PROWLER_VERSION' (must be N.N.N)" >&2
+ echo "::error::Invalid version syntax: '$PROWLER_VERSION' (must be X.Y.Z)"
exit 1
fi
- - name: Bump versions in files
+ bump-minor-version:
+ needs: detect-release-type
+ if: needs.detect-release-type.outputs.is_minor == 'true'
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Calculate next minor version
run: |
- echo "Using PROWLER_VERSION=$PROWLER_VERSION"
- echo "Using BUMP_VERSION_TO=$BUMP_VERSION_TO"
+ MAJOR_VERSION=${{ needs.detect-release-type.outputs.major_version }}
+ MINOR_VERSION=${{ needs.detect-release-type.outputs.minor_version }}
- set -e
+ NEXT_MINOR_VERSION=${MAJOR_VERSION}.$((MINOR_VERSION + 1)).0
+ echo "NEXT_MINOR_VERSION=${NEXT_MINOR_VERSION}" >> "${GITHUB_ENV}"
- echo "Bumping version in pyproject.toml ..."
- sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${BUMP_VERSION_TO}\"|" pyproject.toml
+ echo "Current version: $PROWLER_VERSION"
+ echo "Next minor version: $NEXT_MINOR_VERSION"
- echo "Bumping version in prowler/config/config.py ..."
- sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${BUMP_VERSION_TO}\"|" prowler/config/config.py
+ - name: Bump versions in files for master
+ run: |
+ set -e
- echo "Bumping version in .env ..."
- sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${BUMP_VERSION_TO}|" .env
+ sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${NEXT_MINOR_VERSION}\"|" pyproject.toml
+ sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${NEXT_MINOR_VERSION}\"|" prowler/config/config.py
+ sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${NEXT_MINOR_VERSION}|" .env
- git --no-pager diff
+ echo "Files modified:"
+ git --no-pager diff
- - name: Create Pull Request
+ - name: Create PR for next minor version to master
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
- author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
- token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- base: ${{ env.TARGET_BRANCH }}
- commit-message: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}"
- branch: "version-bump-to-v${{ env.BUMP_VERSION_TO }}"
- title: "chore(release): Bump version to v${{ env.BUMP_VERSION_TO }}"
- labels: no-changelog
- body: |
- ### Description
+ author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ base: master
+ commit-message: 'chore(release): Bump version to v${{ env.NEXT_MINOR_VERSION }}'
+ branch: version-bump-to-v${{ env.NEXT_MINOR_VERSION }}
+ title: 'chore(release): Bump version to v${{ env.NEXT_MINOR_VERSION }}'
+ labels: no-changelog
+ body: |
+ ### Description
- Bump Prowler version to v${{ env.BUMP_VERSION_TO }}
+ Bump Prowler version to v${{ env.NEXT_MINOR_VERSION }} after releasing v${{ env.PROWLER_VERSION }}.
- ### License
+ ### License
- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
+ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
- - name: Handle patch version for minor release
- if: env.FIX_VERSION == '0'
+ - name: Checkout version branch
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ ref: v${{ needs.detect-release-type.outputs.major_version }}.${{ needs.detect-release-type.outputs.minor_version }}
+
+ - name: Calculate first patch version
run: |
- echo "Using PROWLER_VERSION=$PROWLER_VERSION"
- echo "Using PATCH_VERSION_TO=$PATCH_VERSION_TO"
+ MAJOR_VERSION=${{ needs.detect-release-type.outputs.major_version }}
+ MINOR_VERSION=${{ needs.detect-release-type.outputs.minor_version }}
- set -e
+ FIRST_PATCH_VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.1
+ VERSION_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
- echo "Bumping version in pyproject.toml ..."
- sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${PATCH_VERSION_TO}\"|" pyproject.toml
+ echo "FIRST_PATCH_VERSION=${FIRST_PATCH_VERSION}" >> "${GITHUB_ENV}"
+ echo "VERSION_BRANCH=${VERSION_BRANCH}" >> "${GITHUB_ENV}"
- echo "Bumping version in prowler/config/config.py ..."
- sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${PATCH_VERSION_TO}\"|" prowler/config/config.py
+ echo "First patch version: $FIRST_PATCH_VERSION"
+ echo "Version branch: $VERSION_BRANCH"
- echo "Bumping version in .env ..."
- sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PATCH_VERSION_TO}|" .env
+ - name: Bump versions in files for version branch
+ run: |
+ set -e
- git --no-pager diff
+ sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${FIRST_PATCH_VERSION}\"|" pyproject.toml
+ sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${FIRST_PATCH_VERSION}\"|" prowler/config/config.py
+ sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${FIRST_PATCH_VERSION}|" .env
- - name: Create Pull Request for patch version
- if: env.FIX_VERSION == '0'
+ echo "Files modified:"
+ git --no-pager diff
+
+ - name: Create PR for first patch version to version branch
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
- author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
- token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- base: ${{ env.VERSION_BRANCH }}
- commit-message: "chore(release): Bump version to v${{ env.PATCH_VERSION_TO }}"
- branch: "version-bump-to-v${{ env.PATCH_VERSION_TO }}"
- title: "chore(release): Bump version to v${{ env.PATCH_VERSION_TO }}"
- labels: no-changelog
- body: |
- ### Description
+ author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ base: ${{ env.VERSION_BRANCH }}
+ commit-message: 'chore(release): Bump version to v${{ env.FIRST_PATCH_VERSION }}'
+ branch: version-bump-to-v${{ env.FIRST_PATCH_VERSION }}
+ title: 'chore(release): Bump version to v${{ env.FIRST_PATCH_VERSION }}'
+ labels: no-changelog
+ body: |
+ ### Description
- Bump Prowler version to v${{ env.PATCH_VERSION_TO }}
+ Bump Prowler version to v${{ env.FIRST_PATCH_VERSION }} in version branch after releasing v${{ env.PROWLER_VERSION }}.
- ### License
+ ### License
- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
+ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
+
+ bump-patch-version:
+ needs: detect-release-type
+ if: needs.detect-release-type.outputs.is_patch == 'true'
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Calculate next patch version
+ run: |
+ MAJOR_VERSION=${{ needs.detect-release-type.outputs.major_version }}
+ MINOR_VERSION=${{ needs.detect-release-type.outputs.minor_version }}
+ PATCH_VERSION=${{ needs.detect-release-type.outputs.patch_version }}
+
+ NEXT_PATCH_VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.$((PATCH_VERSION + 1))
+ VERSION_BRANCH=v${MAJOR_VERSION}.${MINOR_VERSION}
+
+ echo "NEXT_PATCH_VERSION=${NEXT_PATCH_VERSION}" >> "${GITHUB_ENV}"
+ echo "VERSION_BRANCH=${VERSION_BRANCH}" >> "${GITHUB_ENV}"
+
+ echo "Current version: $PROWLER_VERSION"
+ echo "Next patch version: $NEXT_PATCH_VERSION"
+ echo "Target branch: $VERSION_BRANCH"
+
+ - name: Bump versions in files for version branch
+ run: |
+ set -e
+
+ sed -i "s|version = \"${PROWLER_VERSION}\"|version = \"${NEXT_PATCH_VERSION}\"|" pyproject.toml
+ sed -i "s|prowler_version = \"${PROWLER_VERSION}\"|prowler_version = \"${NEXT_PATCH_VERSION}\"|" prowler/config/config.py
+ sed -i "s|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${PROWLER_VERSION}|NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${NEXT_PATCH_VERSION}|" .env
+
+ echo "Files modified:"
+ git --no-pager diff
+
+ - name: Create PR for next patch version to version branch
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
+ with:
+ author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ base: ${{ env.VERSION_BRANCH }}
+ commit-message: 'chore(release): Bump version to v${{ env.NEXT_PATCH_VERSION }}'
+ branch: version-bump-to-v${{ env.NEXT_PATCH_VERSION }}
+ title: 'chore(release): Bump version to v${{ env.NEXT_PATCH_VERSION }}'
+ labels: no-changelog
+ body: |
+ ### Description
+
+ Bump Prowler version to v${{ env.NEXT_PATCH_VERSION }} after releasing v${{ env.PROWLER_VERSION }}.
+
+ ### License
+
+ By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
diff --git a/.github/workflows/sdk-code-quality.yml b/.github/workflows/sdk-code-quality.yml
new file mode 100644
index 0000000000..b32324d8cb
--- /dev/null
+++ b/.github/workflows/sdk-code-quality.yml
@@ -0,0 +1,90 @@
+name: 'SDK: Code Quality'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ sdk-code-quality:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ python-version:
+ - '3.9'
+ - '3.10'
+ - '3.11'
+ - '3.12'
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for SDK changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ./**
+ files_ignore: |
+ .github/**
+ prowler/CHANGELOG.md
+ docs/**
+ permissions/**
+ api/**
+ ui/**
+ dashboard/**
+ mcp_server/**
+ README.md
+ mkdocs.yml
+ .backportrc.json
+ .env
+ docker-compose*
+ examples/**
+ .gitignore
+ contrib/**
+
+ - name: Install Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: pipx install poetry==2.1.1
+
+ - name: Set up Python ${{ matrix.python-version }}
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ matrix.python-version }}
+ cache: 'poetry'
+
+ - name: Install dependencies
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: |
+ poetry install --no-root
+ poetry run pip list
+
+ - name: Check Poetry lock file
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry check --lock
+
+ - name: Lint with flake8
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib,ui,api
+
+ - name: Check format with black
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run black --exclude api ui --check .
+
+ - name: Lint with pylint
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run pylint --disable=W,C,R,E -j 0 -rn -sn prowler/
diff --git a/.github/workflows/sdk-codeql.yml b/.github/workflows/sdk-codeql.yml
index 3f720a23d5..590ba52d34 100644
--- a/.github/workflows/sdk-codeql.yml
+++ b/.github/workflows/sdk-codeql.yml
@@ -1,44 +1,41 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: SDK - CodeQL
+name: 'SDK: CodeQL'
on:
push:
branches:
- - "master"
- - "v3"
- - "v4.*"
- - "v5.*"
- paths-ignore:
- - 'ui/**'
- - 'api/**'
- - '.github/**'
+ - 'master'
+ - 'v5.*'
+ paths:
+ - 'prowler/**'
+ - 'tests/**'
+ - 'pyproject.toml'
+ - '.github/workflows/sdk-codeql.yml'
+ - '.github/codeql/sdk-codeql-config.yml'
+ - '!prowler/CHANGELOG.md'
pull_request:
branches:
- - "master"
- - "v3"
- - "v4.*"
- - "v5.*"
- paths-ignore:
- - 'ui/**'
- - 'api/**'
- - '.github/**'
+ - 'master'
+ - 'v5.*'
+ paths:
+ - 'prowler/**'
+ - 'tests/**'
+ - 'pyproject.toml'
+ - '.github/workflows/sdk-codeql.yml'
+ - '.github/codeql/sdk-codeql-config.yml'
+ - '!prowler/CHANGELOG.md'
schedule:
- cron: '00 12 * * *'
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
- analyze:
- name: Analyze
+ sdk-analyze:
+ if: github.repository == 'prowler-cloud/prowler'
+ name: CodeQL Security Analysis
runs-on: ubuntu-latest
+ timeout-minutes: 30
permissions:
actions: read
contents: read
@@ -47,21 +44,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: [ 'python' ]
- # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+ language:
+ - 'python'
steps:
- - name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
- with:
- languages: ${{ matrix.language }}
- config-file: ./.github/codeql/sdk-codeql-config.yml
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
+ with:
+ languages: ${{ matrix.language }}
+ config-file: ./.github/codeql/sdk-codeql-config.yml
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
- with:
- category: "/language:${{matrix.language}}"
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
+ with:
+ category: '/language:${{ matrix.language }}'
diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml
new file mode 100644
index 0000000000..72b57ac246
--- /dev/null
+++ b/.github/workflows/sdk-container-build-push.yml
@@ -0,0 +1,266 @@
+name: 'SDK: Container Build and Push'
+
+on:
+ push:
+ branches:
+ - 'v3' # For v3-latest
+ - 'v4.6' # For v4-latest
+ - 'master' # For latest
+ paths-ignore:
+ - '.github/**'
+ - '!.github/workflows/sdk-container-build-push.yml'
+ - 'README.md'
+ - 'docs/**'
+ - 'ui/**'
+ - 'api/**'
+ release:
+ types:
+ - 'published'
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ # Container configuration
+ IMAGE_NAME: prowler
+ DOCKERFILE_PATH: ./Dockerfile
+
+ # Python configuration
+ PYTHON_VERSION: '3.12'
+
+ # Tags (dynamically set based on version)
+ LATEST_TAG: latest
+ STABLE_TAG: stable
+
+ # Container registries
+ PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
+ PROWLERCLOUD_DOCKERHUB_IMAGE: prowler
+
+ # AWS configuration (for ECR)
+ AWS_REGION: us-east-1
+
+jobs:
+ container-build-push:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ${{ matrix.runner }}
+ strategy:
+ matrix:
+ include:
+ - platform: linux/amd64
+ runner: ubuntu-latest
+ arch: amd64
+ - platform: linux/arm64
+ runner: ubuntu-24.04-arm
+ arch: arm64
+ timeout-minutes: 45
+ permissions:
+ contents: read
+ packages: write
+ outputs:
+ prowler_version: ${{ steps.get-prowler-version.outputs.prowler_version }}
+ prowler_version_major: ${{ steps.get-prowler-version.outputs.prowler_version_major }}
+ latest_tag: ${{ steps.get-prowler-version.outputs.latest_tag }}
+ stable_tag: ${{ steps.get-prowler-version.outputs.stable_tag }}
+ env:
+ POETRY_VIRTUALENVS_CREATE: 'false'
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Set up Python ${{ env.PYTHON_VERSION }}
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ env.PYTHON_VERSION }}
+
+ - name: Install Poetry
+ run: |
+ pipx install poetry==2.1.1
+ pipx inject poetry poetry-bumpversion
+
+ - name: Get Prowler version and set tags
+ id: get-prowler-version
+ run: |
+ PROWLER_VERSION="$(poetry version -s 2>/dev/null)"
+ echo "prowler_version=${PROWLER_VERSION}" >> "${GITHUB_OUTPUT}"
+ echo "PROWLER_VERSION=${PROWLER_VERSION}" >> "${GITHUB_ENV}"
+
+ # Extract major version
+ PROWLER_VERSION_MAJOR="${PROWLER_VERSION%%.*}"
+ echo "prowler_version_major=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_OUTPUT}"
+ echo "PROWLER_VERSION_MAJOR=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_ENV}"
+
+ # Set version-specific tags
+ case ${PROWLER_VERSION_MAJOR} in
+ 3)
+ echo "LATEST_TAG=v3-latest" >> "${GITHUB_ENV}"
+ echo "STABLE_TAG=v3-stable" >> "${GITHUB_ENV}"
+ echo "latest_tag=v3-latest" >> "${GITHUB_OUTPUT}"
+ echo "stable_tag=v3-stable" >> "${GITHUB_OUTPUT}"
+ echo "ā Prowler v3 detected - tags: v3-latest, v3-stable"
+ ;;
+ 4)
+ echo "LATEST_TAG=v4-latest" >> "${GITHUB_ENV}"
+ echo "STABLE_TAG=v4-stable" >> "${GITHUB_ENV}"
+ echo "latest_tag=v4-latest" >> "${GITHUB_OUTPUT}"
+ echo "stable_tag=v4-stable" >> "${GITHUB_OUTPUT}"
+ echo "ā Prowler v4 detected - tags: v4-latest, v4-stable"
+ ;;
+ 5)
+ echo "LATEST_TAG=latest" >> "${GITHUB_ENV}"
+ echo "STABLE_TAG=stable" >> "${GITHUB_ENV}"
+ echo "latest_tag=latest" >> "${GITHUB_OUTPUT}"
+ echo "stable_tag=stable" >> "${GITHUB_OUTPUT}"
+ echo "ā Prowler v5 detected - tags: latest, stable"
+ ;;
+ *)
+ echo "::error::Unsupported Prowler major version: ${PROWLER_VERSION_MAJOR}"
+ exit 1
+ ;;
+ esac
+
+ - name: Login to DockerHub
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Login to Public ECR
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ registry: public.ecr.aws
+ username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }}
+ password: ${{ secrets.PUBLIC_ECR_AWS_SECRET_ACCESS_KEY }}
+ env:
+ AWS_REGION: ${{ env.AWS_REGION }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build and push SDK container for ${{ matrix.arch }}
+ if: github.event_name == 'push' || github.event_name == 'release'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: .
+ file: ${{ env.DOCKERFILE_PATH }}
+ push: true
+ platforms: ${{ matrix.platform }}
+ tags: |
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}-${{ matrix.arch }}
+ cache-from: type=gha,scope=${{ matrix.arch }}
+ cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
+
+ - name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: SDK
+ RELEASE_TAG: ${{ env.PROWLER_VERSION }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+ - name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: SDK
+ RELEASE_TAG: ${{ env.PROWLER_VERSION }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+ step-outcome: ${{ steps.container-push.outcome }}
+
+ # Create and push multi-architecture manifest
+ create-manifest:
+ needs: [container-build-push]
+ if: github.event_name == 'push' || github.event_name == 'release'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Login to DockerHub
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Create and push manifests for push event
+ if: github.event_name == 'push'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }} \
+ -t ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }} \
+ -t ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-arm64
+
+ - name: Create and push manifests for release event
+ if: github.event_name == 'release'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ needs.container-build-push.outputs.prowler_version }} \
+ -t ${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ needs.container-build-push.outputs.stable_tag }} \
+ -t ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ needs.container-build-push.outputs.prowler_version }} \
+ -t ${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ needs.container-build-push.outputs.stable_tag }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.prowler_version }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.stable_tag }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-arm64
+
+ - name: Install regctl
+ if: always()
+ uses: regclient/actions/regctl-installer@main
+
+ - name: Cleanup intermediate architecture tags
+ if: always()
+ run: |
+ echo "Cleaning up intermediate tags..."
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-amd64" || true
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.container-build-push.outputs.latest_tag }}-arm64" || true
+ echo "Cleanup completed"
+
+ dispatch-v3-deployment:
+ if: needs.container-build-push.outputs.prowler_version_major == '3'
+ needs: container-build-push
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+
+ steps:
+ - name: Calculate short SHA
+ id: short-sha
+ run: echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
+
+ - name: Dispatch v3 deployment (latest)
+ if: github.event_name == 'push'
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ repository: ${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}
+ event-type: dispatch
+ client-payload: '{"version":"v3-latest","tag":"${{ steps.short-sha.outputs.short_sha }}"}'
+
+ - name: Dispatch v3 deployment (release)
+ if: github.event_name == 'release'
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ repository: ${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}
+ event-type: dispatch
+ client-payload: '{"version":"release","tag":"${{ needs.container-build-push.outputs.prowler_version }}"}'
diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml
new file mode 100644
index 0000000000..4e8a7cf2ad
--- /dev/null
+++ b/.github/workflows/sdk-container-checks.yml
@@ -0,0 +1,103 @@
+name: 'SDK: Container Checks'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ IMAGE_NAME: prowler
+
+jobs:
+ sdk-dockerfile-lint:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check if Dockerfile changed
+ id: dockerfile-changed
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: Dockerfile
+
+ - name: Lint Dockerfile with Hadolint
+ if: steps.dockerfile-changed.outputs.any_changed == 'true'
+ uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
+ with:
+ dockerfile: Dockerfile
+ ignore: DL3013
+
+ sdk-container-build-and-scan:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for SDK changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ./**
+ files_ignore: |
+ .github/**
+ prowler/CHANGELOG.md
+ docs/**
+ permissions/**
+ api/**
+ ui/**
+ dashboard/**
+ mcp_server/**
+ README.md
+ mkdocs.yml
+ .backportrc.json
+ .env
+ docker-compose*
+ examples/**
+ .gitignore
+ contrib/**
+
+ - name: Set up Docker Buildx
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build SDK container
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: .
+ push: false
+ load: true
+ tags: ${{ env.IMAGE_NAME }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Scan SDK container with Trivy
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/trivy-scan
+ with:
+ image-name: ${{ env.IMAGE_NAME }}
+ image-tag: ${{ github.sha }}
+ fail-on-critical: 'false'
+ severity: 'CRITICAL'
diff --git a/.github/workflows/sdk-pull-request.yml b/.github/workflows/sdk-pull-request.yml
deleted file mode 100644
index f6d9df6cd5..0000000000
--- a/.github/workflows/sdk-pull-request.yml
+++ /dev/null
@@ -1,256 +0,0 @@
-name: SDK - Pull Request
-
-on:
- push:
- branches:
- - "master"
- - "v3"
- - "v4.*"
- - "v5.*"
- pull_request:
- branches:
- - "master"
- - "v3"
- - "v4.*"
- - "v5.*"
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: ["3.9", "3.10", "3.11", "3.12"]
-
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Test if changes are in not ignored paths
- id: are-non-ignored-files-changed
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: ./**
- files_ignore: |
- .github/**
- docs/**
- permissions/**
- api/**
- ui/**
- prowler/CHANGELOG.md
- README.md
- mkdocs.yml
- .backportrc.json
- .env
- docker-compose*
- examples/**
- .gitignore
-
- - name: Install poetry
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- python -m pip install --upgrade pip
- pipx install poetry==2.1.1
-
- - name: Set up Python ${{ matrix.python-version }}
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- with:
- python-version: ${{ matrix.python-version }}
- cache: "poetry"
-
- - name: Install dependencies
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry install --no-root
- poetry run pip list
- VERSION=$(curl --silent "https://api.github.com/repos/hadolint/hadolint/releases/latest" | \
- grep '"tag_name":' | \
- sed -E 's/.*"v([^"]+)".*/\1/' \
- ) && curl -L -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64" \
- && chmod +x /tmp/hadolint
-
- - name: Poetry check
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry check --lock
-
- - name: Lint with flake8
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run flake8 . --ignore=E266,W503,E203,E501,W605,E128 --exclude contrib,ui,api
-
- - name: Checking format with black
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run black --exclude api ui --check .
-
- - name: Lint with pylint
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run pylint --disable=W,C,R,E -j 0 -rn -sn prowler/
-
- - name: Bandit
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run bandit -q -lll -x '*_test.py,./contrib/,./api/,./ui' -r .
-
- - name: Safety
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run safety check --ignore 70612 -r pyproject.toml
-
- - name: Vulture
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run vulture --exclude "contrib,api,ui" --min-confidence 100 .
-
- - name: Dockerfile - Check if Dockerfile has changed
- id: dockerfile-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- Dockerfile
-
- - name: Hadolint
- if: steps.dockerfile-changed-files.outputs.any_changed == 'true'
- run: |
- /tmp/hadolint Dockerfile --ignore=DL3013
-
- # Test AWS
- - name: AWS - Check if any file has changed
- id: aws-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/aws/**
- ./tests/providers/aws/**
- .poetry.lock
-
- - name: AWS - Test
- if: steps.aws-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/aws --cov-report=xml:aws_coverage.xml tests/providers/aws
-
- # Test Azure
- - name: Azure - Check if any file has changed
- id: azure-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/azure/**
- ./tests/providers/azure/**
- .poetry.lock
-
- - name: Azure - Test
- if: steps.azure-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/azure --cov-report=xml:azure_coverage.xml tests/providers/azure
-
- # Test GCP
- - name: GCP - Check if any file has changed
- id: gcp-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/gcp/**
- ./tests/providers/gcp/**
- .poetry.lock
-
- - name: GCP - Test
- if: steps.gcp-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/gcp --cov-report=xml:gcp_coverage.xml tests/providers/gcp
-
- # Test Kubernetes
- - name: Kubernetes - Check if any file has changed
- id: kubernetes-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/kubernetes/**
- ./tests/providers/kubernetes/**
- .poetry.lock
-
- - name: Kubernetes - Test
- if: steps.kubernetes-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/kubernetes --cov-report=xml:kubernetes_coverage.xml tests/providers/kubernetes
-
- # Test GitHub
- - name: GitHub - Check if any file has changed
- id: github-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/github/**
- ./tests/providers/github/**
- .poetry.lock
-
- - name: GitHub - Test
- if: steps.github-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/github --cov-report=xml:github_coverage.xml tests/providers/github
-
- # Test NHN
- - name: NHN - Check if any file has changed
- id: nhn-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/nhn/**
- ./tests/providers/nhn/**
- .poetry.lock
-
- - name: NHN - Test
- if: steps.nhn-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/nhn --cov-report=xml:nhn_coverage.xml tests/providers/nhn
-
- # Test M365
- - name: M365 - Check if any file has changed
- id: m365-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/m365/**
- ./tests/providers/m365/**
- .poetry.lock
-
- - name: M365 - Test
- if: steps.m365-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/m365 --cov-report=xml:m365_coverage.xml tests/providers/m365
-
- # Test IaC
- - name: IaC - Check if any file has changed
- id: iac-changed-files
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5
- with:
- files: |
- ./prowler/providers/iac/**
- ./tests/providers/iac/**
- .poetry.lock
-
- - name: IaC - Test
- if: steps.iac-changed-files.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/providers/iac --cov-report=xml:iac_coverage.xml tests/providers/iac
-
- # Common Tests
- - name: Lib - Test
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/lib --cov-report=xml:lib_coverage.xml tests/lib
-
- - name: Config - Test
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- run: |
- poetry run pytest -n auto --cov=./prowler/config --cov-report=xml:config_coverage.xml tests/config
-
- # Codecov
- - name: Upload coverage reports to Codecov
- if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
- env:
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- with:
- flags: prowler
- files: ./aws_coverage.xml,./azure_coverage.xml,./gcp_coverage.xml,./kubernetes_coverage.xml,./github_coverage.xml,./nhn_coverage.xml,./m365_coverage.xml,./lib_coverage.xml,./config_coverage.xml
diff --git a/.github/workflows/sdk-pypi-release.yml b/.github/workflows/sdk-pypi-release.yml
index 07d6ca5a6f..0f74ba054c 100644
--- a/.github/workflows/sdk-pypi-release.yml
+++ b/.github/workflows/sdk-pypi-release.yml
@@ -1,98 +1,119 @@
-name: SDK - PyPI release
+name: 'SDK: PyPI Release'
on:
release:
- types: [published]
+ types:
+ - 'published'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
+ cancel-in-progress: false
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
- PYTHON_VERSION: 3.11
- # CACHE: "poetry"
+ PYTHON_VERSION: '3.12'
jobs:
- repository-check:
- name: Repository check
+ validate-release:
+ if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
outputs:
- is_repo: ${{ steps.repository_check.outputs.is_repo }}
- steps:
- - name: Repository check
- id: repository_check
- working-directory: /tmp
- run: |
- if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
- then
- echo "is_repo=true" >> "${GITHUB_OUTPUT}"
- else
- echo "This action only runs for prowler-cloud/prowler"
- echo "is_repo=false" >> "${GITHUB_OUTPUT}"
- fi
+ prowler_version: ${{ steps.parse-version.outputs.version }}
+ major_version: ${{ steps.parse-version.outputs.major }}
- release-prowler-job:
- runs-on: ubuntu-latest
- needs: repository-check
- if: needs.repository-check.outputs.is_repo == 'true'
- env:
- POETRY_VIRTUALENVS_CREATE: "false"
- name: Release Prowler to PyPI
steps:
- - name: Repository check
- working-directory: /tmp
- run: |
- if [[ "${{ github.repository }}" != "prowler-cloud/prowler" ]]; then
- echo "This action only runs for prowler-cloud/prowler"
- exit 1
- fi
-
- - name: Get Prowler version
+ - name: Parse and validate version
+ id: parse-version
run: |
PROWLER_VERSION="${{ env.RELEASE_TAG }}"
+ echo "version=${PROWLER_VERSION}" >> "${GITHUB_OUTPUT}"
- case ${PROWLER_VERSION%%.*} in
- 3)
- echo "Releasing Prowler v3 with tag ${PROWLER_VERSION}"
+ # Extract major version
+ MAJOR_VERSION="${PROWLER_VERSION%%.*}"
+ echo "major=${MAJOR_VERSION}" >> "${GITHUB_OUTPUT}"
+
+ # Validate major version
+ case ${MAJOR_VERSION} in
+ 3|4|5)
+ echo "ā Releasing Prowler v${MAJOR_VERSION} with tag ${PROWLER_VERSION}"
;;
- 4)
- echo "Releasing Prowler v4 with tag ${PROWLER_VERSION}"
- ;;
- 5)
- echo "Releasing Prowler v5 with tag ${PROWLER_VERSION}"
- ;;
- *)
- echo "Releasing another Prowler major version, aborting..."
+ *)
+ echo "::error::Unsupported Prowler major version: ${MAJOR_VERSION}"
exit 1
;;
esac
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ publish-prowler:
+ needs: validate-release
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ id-token: write
+ environment:
+ name: pypi-prowler
+ url: https://pypi.org/project/prowler/${{ needs.validate-release.outputs.prowler_version }}/
- - name: Install dependencies
- run: |
- pipx install poetry==2.1.1
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- - name: Setup Python
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+ - name: Install Poetry
+ run: pipx install poetry==2.1.1
+
+ - name: Set up Python ${{ env.PYTHON_VERSION }}
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- # cache: ${{ env.CACHE }}
+ cache: 'poetry'
- name: Build Prowler package
- run: |
- poetry build
+ run: poetry build
- name: Publish Prowler package to PyPI
- run: |
- poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
- poetry publish
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
+ with:
+ print-hash: true
- - name: Replicate PyPI package
+ publish-prowler-cloud:
+ needs: validate-release
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ id-token: write
+ environment:
+ name: pypi-prowler-cloud
+ url: https://pypi.org/project/prowler-cloud/${{ needs.validate-release.outputs.prowler_version }}/
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Install Poetry
+ run: pipx install poetry==2.1.1
+
+ - name: Set up Python ${{ env.PYTHON_VERSION }}
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ env.PYTHON_VERSION }}
+ cache: 'poetry'
+
+ - name: Install toml package
+ run: pip install toml
+
+ - name: Replicate PyPI package for prowler-cloud
run: |
- rm -rf ./dist && rm -rf ./build && rm -rf prowler.egg-info
- pip install toml
+ rm -rf ./dist ./build prowler.egg-info
python util/replicate_pypi_package.py
- poetry build
+
+ - name: Build prowler-cloud package
+ run: poetry build
- name: Publish prowler-cloud package to PyPI
- run: |
- poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
- poetry publish
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
+ with:
+ print-hash: true
diff --git a/.github/workflows/sdk-refresh-aws-services-regions.yml b/.github/workflows/sdk-refresh-aws-services-regions.yml
index 036b75bb84..884b677294 100644
--- a/.github/workflows/sdk-refresh-aws-services-regions.yml
+++ b/.github/workflows/sdk-refresh-aws-services-regions.yml
@@ -1,68 +1,90 @@
-# This is a basic workflow to help you get started with Actions
-
-name: SDK - Refresh AWS services' regions
+name: 'SDK: Refresh AWS Regions'
on:
schedule:
- - cron: "0 9 * * 1" # runs at 09:00 UTC every Monday
+ - cron: '0 9 * * 1' # Every Monday at 09:00 UTC
+ workflow_dispatch:
+
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: false
env:
- GITHUB_BRANCH: "master"
- AWS_REGION_DEV: us-east-1
+ PYTHON_VERSION: '3.12'
+ AWS_REGION: 'us-east-1'
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
- # This workflow contains a single job called "build"
- build:
- # The type of runner that the job will run on
+ refresh-aws-regions:
+ if: github.repository == 'prowler-cloud/prowler'
runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
id-token: write
pull-requests: write
contents: write
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- ref: ${{ env.GITHUB_BRANCH }}
- - name: setup python
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
- python-version: 3.9 #install the python needed
+ ref: 'master'
+
+ - name: Set up Python ${{ env.PYTHON_VERSION }}
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ env.PYTHON_VERSION }}
+ cache: 'pip'
- name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install boto3
+ run: pip install boto3
- - name: Configure AWS Credentials -- DEV
- uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
+ - name: Configure AWS credentials
+ uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0
with:
- aws-region: ${{ env.AWS_REGION_DEV }}
+ aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ secrets.DEV_IAM_ROLE_ARN }}
- role-session-name: refresh-AWS-regions-dev
+ role-session-name: prowler-refresh-aws-regions
- # Runs a single command using the runners shell
- - name: Run a one-line script
- run: python3 util/update_aws_services_regions.py
+ - name: Update AWS services regions
+ run: python util/update_aws_services_regions.py
- # Create pull request
- - name: Create Pull Request
+ - name: Create pull request
+ id: create-pr
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
- author: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- commit-message: "feat(regions_update): Update regions for AWS services"
- branch: "aws-services-regions-updated-${{ github.sha }}"
- labels: "status/waiting-for-revision, severity/low, provider/aws"
- title: "chore(regions_update): Changes in regions for AWS services"
+ author: 'prowler-bot <179230569+prowler-bot@users.noreply.github.com>'
+ committer: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>'
+ commit-message: 'feat(aws): update regions for AWS services'
+ branch: 'aws-regions-update-${{ github.run_number }}'
+ title: 'feat(aws): Update regions for AWS services'
+ labels: |
+ status/waiting-for-revision
+ severity/low
+ provider/aws
+ no-changelog
body: |
### Description
- This PR updates the regions for AWS services.
+ Automated update of AWS service regions from the official AWS IP ranges.
+
+ **Trigger:** ${{ github.event_name == 'schedule' && 'Scheduled (weekly)' || github.event_name == 'workflow_dispatch' && 'Manual' || 'Workflow update' }}
+ **Run:** [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
+
+ ### Checklist
+
+ - [x] This is an automated update from AWS official sources
+ - [x] No manual review of region data required
### License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
+
+ - name: PR creation result
+ run: |
+ if [[ "${{ steps.create-pr.outputs.pull-request-number }}" ]]; then
+ echo "ā Pull request #${{ steps.create-pr.outputs.pull-request-number }} created successfully"
+ echo "URL: ${{ steps.create-pr.outputs.pull-request-url }}"
+ else
+ echo "ā No changes detected - AWS regions are up to date"
+ fi
diff --git a/.github/workflows/sdk-security.yml b/.github/workflows/sdk-security.yml
new file mode 100644
index 0000000000..a15bd2539f
--- /dev/null
+++ b/.github/workflows/sdk-security.yml
@@ -0,0 +1,77 @@
+name: 'SDK: Security'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ sdk-security-scans:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for SDK changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ./**
+ files_ignore: |
+ .github/**
+ prowler/CHANGELOG.md
+ docs/**
+ permissions/**
+ api/**
+ ui/**
+ dashboard/**
+ mcp_server/**
+ README.md
+ mkdocs.yml
+ .backportrc.json
+ .env
+ docker-compose*
+ examples/**
+ .gitignore
+ contrib/**
+
+ - name: Install Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: pipx install poetry==2.1.1
+
+ - name: Set up Python 3.12
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install dependencies
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry install --no-root
+
+ - name: Security scan with Bandit
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run bandit -q -lll -x '*_test.py,./contrib/,./api/,./ui' -r .
+
+ - name: Security scan with Safety
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run safety check --ignore 70612 -r pyproject.toml
+
+ - name: Dead code detection with Vulture
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry run vulture --exclude "contrib,api,ui" --min-confidence 100 .
diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml
new file mode 100644
index 0000000000..b01c5e7778
--- /dev/null
+++ b/.github/workflows/sdk-tests.yml
@@ -0,0 +1,360 @@
+name: 'SDK: Tests'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ sdk-tests:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 120
+ permissions:
+ contents: read
+ strategy:
+ matrix:
+ python-version:
+ - '3.9'
+ - '3.10'
+ - '3.11'
+ - '3.12'
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for SDK changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ./**
+ files_ignore: |
+ .github/**
+ prowler/CHANGELOG.md
+ docs/**
+ permissions/**
+ api/**
+ ui/**
+ dashboard/**
+ mcp_server/**
+ README.md
+ mkdocs.yml
+ .backportrc.json
+ .env
+ docker-compose*
+ examples/**
+ .gitignore
+ contrib/**
+
+ - name: Install Poetry
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: pipx install poetry==2.1.1
+
+ - name: Set up Python ${{ matrix.python-version }}
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
+ with:
+ python-version: ${{ matrix.python-version }}
+ cache: 'poetry'
+
+ - name: Install dependencies
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: poetry install --no-root
+
+ # AWS Provider
+ - name: Check if AWS files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-aws
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/aws/**
+ ./tests/**/aws/**
+ ./poetry.lock
+
+ - name: Run AWS tests
+ if: steps.changed-aws.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/aws --cov-report=xml:aws_coverage.xml tests/providers/aws
+
+ - name: Upload AWS coverage to Codecov
+ if: steps.changed-aws.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-aws
+ files: ./aws_coverage.xml
+
+ # Azure Provider
+ - name: Check if Azure files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-azure
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/azure/**
+ ./tests/**/azure/**
+ ./poetry.lock
+
+ - name: Run Azure tests
+ if: steps.changed-azure.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/azure --cov-report=xml:azure_coverage.xml tests/providers/azure
+
+ - name: Upload Azure coverage to Codecov
+ if: steps.changed-azure.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-azure
+ files: ./azure_coverage.xml
+
+ # GCP Provider
+ - name: Check if GCP files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-gcp
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/gcp/**
+ ./tests/**/gcp/**
+ ./poetry.lock
+
+ - name: Run GCP tests
+ if: steps.changed-gcp.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/gcp --cov-report=xml:gcp_coverage.xml tests/providers/gcp
+
+ - name: Upload GCP coverage to Codecov
+ if: steps.changed-gcp.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-gcp
+ files: ./gcp_coverage.xml
+
+ # Kubernetes Provider
+ - name: Check if Kubernetes files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-kubernetes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/kubernetes/**
+ ./tests/**/kubernetes/**
+ ./poetry.lock
+
+ - name: Run Kubernetes tests
+ if: steps.changed-kubernetes.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/kubernetes --cov-report=xml:kubernetes_coverage.xml tests/providers/kubernetes
+
+ - name: Upload Kubernetes coverage to Codecov
+ if: steps.changed-kubernetes.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-kubernetes
+ files: ./kubernetes_coverage.xml
+
+ # GitHub Provider
+ - name: Check if GitHub files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-github
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/github/**
+ ./tests/**/github/**
+ ./poetry.lock
+
+ - name: Run GitHub tests
+ if: steps.changed-github.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/github --cov-report=xml:github_coverage.xml tests/providers/github
+
+ - name: Upload GitHub coverage to Codecov
+ if: steps.changed-github.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-github
+ files: ./github_coverage.xml
+
+ # NHN Provider
+ - name: Check if NHN files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-nhn
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/nhn/**
+ ./tests/**/nhn/**
+ ./poetry.lock
+
+ - name: Run NHN tests
+ if: steps.changed-nhn.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/nhn --cov-report=xml:nhn_coverage.xml tests/providers/nhn
+
+ - name: Upload NHN coverage to Codecov
+ if: steps.changed-nhn.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-nhn
+ files: ./nhn_coverage.xml
+
+ # M365 Provider
+ - name: Check if M365 files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-m365
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/m365/**
+ ./tests/**/m365/**
+ ./poetry.lock
+
+ - name: Run M365 tests
+ if: steps.changed-m365.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/m365 --cov-report=xml:m365_coverage.xml tests/providers/m365
+
+ - name: Upload M365 coverage to Codecov
+ if: steps.changed-m365.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-m365
+ files: ./m365_coverage.xml
+
+ # IaC Provider
+ - name: Check if IaC files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-iac
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/iac/**
+ ./tests/**/iac/**
+ ./poetry.lock
+
+ - name: Run IaC tests
+ if: steps.changed-iac.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/iac --cov-report=xml:iac_coverage.xml tests/providers/iac
+
+ - name: Upload IaC coverage to Codecov
+ if: steps.changed-iac.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-iac
+ files: ./iac_coverage.xml
+
+ # MongoDB Atlas Provider
+ - name: Check if MongoDB Atlas files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-mongodbatlas
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/mongodbatlas/**
+ ./tests/**/mongodbatlas/**
+ ./poetry.lock
+
+ - name: Run MongoDB Atlas tests
+ if: steps.changed-mongodbatlas.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/mongodbatlas --cov-report=xml:mongodbatlas_coverage.xml tests/providers/mongodbatlas
+
+ - name: Upload MongoDB Atlas coverage to Codecov
+ if: steps.changed-mongodbatlas.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-mongodbatlas
+ files: ./mongodbatlas_coverage.xml
+
+ # OCI Provider
+ - name: Check if OCI files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-oraclecloud
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/**/oraclecloud/**
+ ./tests/**/oraclecloud/**
+ ./poetry.lock
+
+ - name: Run OCI tests
+ if: steps.changed-oraclecloud.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/providers/oraclecloud --cov-report=xml:oraclecloud_coverage.xml tests/providers/oraclecloud
+
+ - name: Upload OCI coverage to Codecov
+ if: steps.changed-oraclecloud.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-oraclecloud
+ files: ./oraclecloud_coverage.xml
+
+ # Lib
+ - name: Check if Lib files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-lib
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/lib/**
+ ./tests/lib/**
+ ./poetry.lock
+
+ - name: Run Lib tests
+ if: steps.changed-lib.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/lib --cov-report=xml:lib_coverage.xml tests/lib
+
+ - name: Upload Lib coverage to Codecov
+ if: steps.changed-lib.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-lib
+ files: ./lib_coverage.xml
+
+ # Config
+ - name: Check if Config files changed
+ if: steps.check-changes.outputs.any_changed == 'true'
+ id: changed-config
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ./prowler/config/**
+ ./tests/config/**
+ ./poetry.lock
+
+ - name: Run Config tests
+ if: steps.changed-config.outputs.any_changed == 'true'
+ run: poetry run pytest -n auto --cov=./prowler/config --cov-report=xml:config_coverage.xml tests/config
+
+ - name: Upload Config coverage to Codecov
+ if: steps.changed-config.outputs.any_changed == 'true'
+ uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ with:
+ flags: prowler-py${{ matrix.python-version }}-config
+ files: ./config_coverage.xml
diff --git a/.github/workflows/ui-build-lint-push-containers.yml b/.github/workflows/ui-build-lint-push-containers.yml
deleted file mode 100644
index bce6ba6a07..0000000000
--- a/.github/workflows/ui-build-lint-push-containers.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-name: UI - Build and Push containers
-
-on:
- push:
- branches:
- - "master"
- paths:
- - "ui/**"
- - ".github/workflows/ui-build-lint-push-containers.yml"
-
- # Uncomment the below code to test this action on PRs
- # pull_request:
- # branches:
- # - "master"
- # paths:
- # - "ui/**"
- # - ".github/workflows/ui-build-lint-push-containers.yml"
-
- release:
- types: [published]
-
-env:
- # Tags
- LATEST_TAG: latest
- RELEASE_TAG: ${{ github.event.release.tag_name }}
- STABLE_TAG: stable
-
- WORKING_DIRECTORY: ./ui
-
- # Container Registries
- PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
- PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-ui
- NEXT_PUBLIC_API_BASE_URL: http://prowler-api:8080/api/v1
-
-jobs:
- repository-check:
- name: Repository check
- runs-on: ubuntu-latest
- outputs:
- is_repo: ${{ steps.repository_check.outputs.is_repo }}
- steps:
- - name: Repository check
- id: repository_check
- working-directory: /tmp
- run: |
- if [[ ${{ github.repository }} == "prowler-cloud/prowler" ]]
- then
- echo "is_repo=true" >> "${GITHUB_OUTPUT}"
- else
- echo "This action only runs for prowler-cloud/prowler"
- echo "is_repo=false" >> "${GITHUB_OUTPUT}"
- fi
-
- # Build Prowler OSS container
- container-build-push:
- needs: repository-check
- if: needs.repository-check.outputs.is_repo == 'true'
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ${{ env.WORKING_DIRECTORY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Set short git commit SHA
- id: vars
- run: |
- shortSha=$(git rev-parse --short ${{ github.sha }})
- echo "SHORT_SHA=${shortSha}" >> $GITHUB_ENV
-
- - name: Login to DockerHub
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
-
- - name: Build and push container image (latest)
- # Comment the following line for testing
- if: github.event_name == 'push'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.WORKING_DIRECTORY }}
- build-args: |
- NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ env.SHORT_SHA }}
- NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
- # Set push: false for testing
- push: true
- tags: |
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.SHORT_SHA }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- - name: Build and push container image (release)
- if: github.event_name == 'release'
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.WORKING_DIRECTORY }}
- build-args: |
- NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v${{ env.RELEASE_TAG }}
- NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
- push: true
- tags: |
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }}
- ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
-
- - name: Trigger deployment
- if: github.event_name == 'push'
- uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
- with:
- token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
- repository: ${{ secrets.CLOUD_DISPATCH }}
- event-type: prowler-ui-deploy
- client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ env.SHORT_SHA }}"}'
diff --git a/.github/workflows/ui-codeql.yml b/.github/workflows/ui-codeql.yml
index e594ddc7fc..2b55cf673c 100644
--- a/.github/workflows/ui-codeql.yml
+++ b/.github/workflows/ui-codeql.yml
@@ -1,36 +1,37 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: UI - CodeQL
+name: 'UI: CodeQL'
on:
push:
branches:
- - "master"
- - "v5.*"
+ - 'master'
+ - 'v5.*'
paths:
- - "ui/**"
+ - 'ui/**'
+ - '.github/workflows/ui-codeql.yml'
+ - '.github/codeql/ui-codeql-config.yml'
+ - '!ui/CHANGELOG.md'
pull_request:
branches:
- - "master"
- - "v5.*"
+ - 'master'
+ - 'v5.*'
paths:
- - "ui/**"
+ - 'ui/**'
+ - '.github/workflows/ui-codeql.yml'
+ - '.github/codeql/ui-codeql-config.yml'
+ - '!ui/CHANGELOG.md'
schedule:
- - cron: "00 12 * * *"
+ - cron: '00 12 * * *'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
- analyze:
- name: Analyze
+ ui-analyze:
+ if: github.repository == 'prowler-cloud/prowler'
+ name: CodeQL Security Analysis
runs-on: ubuntu-latest
+ timeout-minutes: 30
permissions:
actions: read
contents: read
@@ -39,21 +40,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: ["javascript"]
- # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+ language:
+ - 'javascript-typescript'
steps:
- name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
+ uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/ui-codeql-config.yml
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
+ uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
with:
- category: "/language:${{matrix.language}}"
+ category: '/language:${{ matrix.language }}'
diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml
new file mode 100644
index 0000000000..34cddc900d
--- /dev/null
+++ b/.github/workflows/ui-container-build-push.yml
@@ -0,0 +1,196 @@
+name: 'UI: Container Build and Push'
+
+on:
+ push:
+ branches:
+ - 'master'
+ paths:
+ - 'ui/**'
+ - '.github/workflows/ui-container-build-push.yml'
+ release:
+ types:
+ - 'published'
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ # Tags
+ LATEST_TAG: latest
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
+ STABLE_TAG: stable
+ WORKING_DIRECTORY: ./ui
+
+ # Container registries
+ PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
+ PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-ui
+
+ # Build args
+ NEXT_PUBLIC_API_BASE_URL: http://prowler-api:8080/api/v1
+
+jobs:
+ setup:
+ if: github.repository == 'prowler-cloud/prowler'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ outputs:
+ short-sha: ${{ steps.set-short-sha.outputs.short-sha }}
+ steps:
+ - name: Calculate short SHA
+ id: set-short-sha
+ run: echo "short-sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
+
+ container-build-push:
+ needs: setup
+ runs-on: ${{ matrix.runner }}
+ strategy:
+ matrix:
+ include:
+ - platform: linux/amd64
+ runner: ubuntu-latest
+ arch: amd64
+ - platform: linux/arm64
+ runner: ubuntu-24.04-arm
+ arch: arm64
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Login to DockerHub
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build and push UI container for ${{ matrix.arch }}
+ if: github.event_name == 'push'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.WORKING_DIRECTORY }}
+ build-args: |
+ NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ needs.setup.outputs.short-sha }}
+ NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
+ push: true
+ platforms: ${{ matrix.platform }}
+ tags: |
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-${{ matrix.arch }}
+ cache-from: type=gha,scope=${{ matrix.arch }}
+ cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
+
+ - name: Build and push UI container for ${{ matrix.arch }}
+ if: github.event_name == 'push' || github.event_name == 'release'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.WORKING_DIRECTORY }}
+ build-args: |
+ NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ github.event_name == 'release' && format('v{0}', env.RELEASE_TAG) || needs.setup.outputs.short_sha }}
+ NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
+ push: true
+ tags: |
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Notify container push started
+ if: github.event_name == 'release'
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: UI
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-started.json"
+
+ - name: Notify container push completed
+ if: github.event_name == 'release' && always()
+ uses: ./.github/actions/slack-notification
+ env:
+ SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }}
+ COMPONENT: UI
+ RELEASE_TAG: ${{ env.RELEASE_TAG }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ with:
+ slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
+ payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json"
+ step-outcome: ${{ steps.container-push.outcome }}
+
+ # Create and push multi-architecture manifest
+ create-manifest:
+ needs: [setup, container-build-push]
+ if: github.event_name == 'push' || github.event_name == 'release'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Login to DockerHub
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Create and push manifests for push event
+ if: github.event_name == 'push'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Create and push manifests for release event
+ if: github.event_name == 'release'
+ run: |
+ docker buildx imagetools create \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.RELEASE_TAG }} \
+ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }} \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64 \
+ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64
+
+ - name: Install regctl
+ if: always()
+ uses: regclient/actions/regctl-installer@main
+
+ - name: Cleanup intermediate architecture tags
+ if: always()
+ run: |
+ echo "Cleaning up intermediate tags..."
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-amd64" || true
+ regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-arm64" || true
+ echo "Cleanup completed"
+
+ trigger-deployment:
+ if: github.event_name == 'push'
+ needs: [setup, container-build-push]
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+
+ steps:
+ - name: Trigger UI deployment
+ uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4.0.0
+ with:
+ token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }}
+ repository: ${{ secrets.CLOUD_DISPATCH }}
+ event-type: ui-prowler-deployment
+ client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ needs.setup.outputs.short-sha }}"}'
diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml
new file mode 100644
index 0000000000..e436c3974a
--- /dev/null
+++ b/.github/workflows/ui-container-checks.yml
@@ -0,0 +1,91 @@
+name: 'UI: Container Checks'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ UI_WORKING_DIR: ./ui
+ IMAGE_NAME: prowler-ui
+
+jobs:
+ ui-dockerfile-lint:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ permissions:
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check if Dockerfile changed
+ id: dockerfile-changed
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ui/Dockerfile
+
+ - name: Lint Dockerfile with Hadolint
+ if: steps.dockerfile-changed.outputs.any_changed == 'true'
+ uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
+ with:
+ dockerfile: ui/Dockerfile
+ ignore: DL3018
+
+ ui-container-build-and-scan:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for UI changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: ui/**
+ files_ignore: |
+ ui/CHANGELOG.md
+ ui/README.md
+
+ - name: Set up Docker Buildx
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Build UI container
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ context: ${{ env.UI_WORKING_DIR }}
+ target: prod
+ push: false
+ load: true
+ tags: ${{ env.IMAGE_NAME }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+ build-args: |
+ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51LwpXXXX
+
+ - name: Scan UI container with Trivy
+ if: github.repository == 'prowler-cloud/prowler' && steps.check-changes.outputs.any_changed == 'true'
+ uses: ./.github/actions/trivy-scan
+ with:
+ image-name: ${{ env.IMAGE_NAME }}
+ image-tag: ${{ github.sha }}
+ fail-on-critical: 'false'
+ severity: 'CRITICAL'
diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml
index 543857a511..ed3b692819 100644
--- a/.github/workflows/ui-e2e-tests.yml
+++ b/.github/workflows/ui-e2e-tests.yml
@@ -18,9 +18,27 @@ jobs:
AUTH_TRUST_HOST: true
NEXTAUTH_URL: 'http://localhost:3000'
NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1'
+ E2E_ADMIN_USER: ${{ secrets.E2E_ADMIN_USER }}
+ E2E_ADMIN_PASSWORD: ${{ secrets.E2E_ADMIN_PASSWORD }}
+ E2E_AWS_PROVIDER_ACCOUNT_ID: ${{ secrets.E2E_AWS_PROVIDER_ACCOUNT_ID }}
+ E2E_AWS_PROVIDER_ACCESS_KEY: ${{ secrets.E2E_AWS_PROVIDER_ACCESS_KEY }}
+ E2E_AWS_PROVIDER_SECRET_KEY: ${{ secrets.E2E_AWS_PROVIDER_SECRET_KEY }}
+ E2E_AWS_PROVIDER_ROLE_ARN: ${{ secrets.E2E_AWS_PROVIDER_ROLE_ARN }}
+ E2E_AZURE_SUBSCRIPTION_ID: ${{ secrets.E2E_AZURE_SUBSCRIPTION_ID }}
+ E2E_AZURE_CLIENT_ID: ${{ secrets.E2E_AZURE_CLIENT_ID }}
+ E2E_AZURE_SECRET_ID: ${{ secrets.E2E_AZURE_SECRET_ID }}
+ E2E_AZURE_TENANT_ID: ${{ secrets.E2E_AZURE_TENANT_ID }}
+ E2E_M365_DOMAIN_ID: ${{ secrets.E2E_M365_DOMAIN_ID }}
+ E2E_M365_CLIENT_ID: ${{ secrets.E2E_M365_CLIENT_ID }}
+ E2E_M365_SECRET_ID: ${{ secrets.E2E_M365_SECRET_ID }}
+ E2E_M365_TENANT_ID: ${{ secrets.E2E_M365_TENANT_ID }}
+ E2E_M365_CERTIFICATE_CONTENT: ${{ secrets.E2E_M365_CERTIFICATE_CONTENT }}
+ E2E_NEW_PASSWORD: ${{ secrets.E2E_NEW_PASSWORD }}
steps:
- name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ - name: Fix API data directory permissions
+ run: docker run --rm -v $(pwd)/_data/api:/data alpine chown -R 1000:1000 /data
- name: Start API services
run: |
# Override docker-compose image tag to use latest instead of stable
@@ -57,7 +75,7 @@ jobs:
echo "All database fixtures loaded successfully!"
'
- name: Setup Node.js environment
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
+ uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: '20.x'
cache: 'npm'
@@ -69,7 +87,7 @@ jobs:
working-directory: ./ui
run: npm run build
- name: Cache Playwright browsers
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
id: playwright-cache
with:
path: ~/.cache/ms-playwright
diff --git a/.github/workflows/ui-pull-request.yml b/.github/workflows/ui-pull-request.yml
deleted file mode 100644
index 1925f6c230..0000000000
--- a/.github/workflows/ui-pull-request.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: UI - Pull Request
-
-on:
- push:
- branches:
- - "master"
- - "v5.*"
- paths:
- - ".github/workflows/ui-pull-request.yml"
- - "ui/**"
- pull_request:
- branches:
- - master
- - "v5.*"
- paths:
- - 'ui/**'
-env:
- UI_WORKING_DIR: ./ui
- IMAGE_NAME: prowler-ui
-
-jobs:
- test-and-coverage:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- os: [ubuntu-latest]
- node-version: [20.x]
- steps:
- - name: Checkout repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- persist-credentials: false
- - name: Setup Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
- with:
- node-version: ${{ matrix.node-version }}
- cache: 'npm'
- cache-dependency-path: './ui/package-lock.json'
- - name: Install dependencies
- working-directory: ./ui
- run: npm ci
- - name: Run Healthcheck
- working-directory: ./ui
- run: npm run healthcheck
- - name: Build the application
- working-directory: ./ui
- run: npm run build
-
- test-container-build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- - name: Build Container
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- context: ${{ env.UI_WORKING_DIR }}
- # Always build using `prod` target
- target: prod
- push: false
- tags: ${{ env.IMAGE_NAME }}:latest
- outputs: type=docker
- build-args: |
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51LwpXXXX
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
new file mode 100644
index 0000000000..a5a5b5fa17
--- /dev/null
+++ b/.github/workflows/ui-tests.yml
@@ -0,0 +1,64 @@
+name: 'UI: Tests'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'v5.*'
+ pull_request:
+ branches:
+ - 'master'
+ - 'v5.*'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ UI_WORKING_DIR: ./ui
+ NODE_VERSION: '20.x'
+
+jobs:
+ ui-tests:
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ defaults:
+ run:
+ working-directory: ./ui
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+ - name: Check for UI changes
+ id: check-changes
+ uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
+ with:
+ files: |
+ ui/**
+ .github/workflows/ui-tests.yml
+ files_ignore: |
+ ui/CHANGELOG.md
+ ui/README.md
+
+ - name: Setup Node.js ${{ env.NODE_VERSION }}
+ if: steps.check-changes.outputs.any_changed == 'true'
+ uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: 'npm'
+ cache-dependency-path: './ui/package-lock.json'
+
+ - name: Install dependencies
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: npm ci
+
+ - name: Run healthcheck
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: npm run healthcheck
+
+ - name: Build application
+ if: steps.check-changes.outputs.any_changed == 'true'
+ run: npm run build
diff --git a/.gitignore b/.gitignore
index 6e7e284566..7792a031b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,21 +39,92 @@ secrets-*/
# JUnit Reports
junit-reports/
-# VSCode files
-.vscode/
+# Test and coverage artifacts
+*_coverage.xml
+pytest_*.xml
+.coverage
+htmlcov/
-# Cursor files
+# VSCode files and settings
+.vscode/
+*.code-workspace
+.vscode-test/
+
+# VSCode extension settings and workspaces
+.history/
+.ionide/
+
+# MCP Server Settings (various locations)
+**/cline_mcp_settings.json
+**/mcp_settings.json
+**/mcp-config.json
+**/mcpServers.json
+.mcp/
+
+# AI Coding Assistants - Cursor
.cursorignore
.cursor/
+.cursorrules
-# RooCode files
+# AI Coding Assistants - RooCode
.roo/
.rooignore
.roomodes
-# Cline files
+# AI Coding Assistants - Cline (formerly Claude Dev)
.cline/
.clineignore
+.clinerules
+
+# AI Coding Assistants - Continue
+.continue/
+continue.json
+.continuerc
+.continuerc.json
+
+# AI Coding Assistants - GitHub Copilot
+.copilot/
+.github/copilot/
+
+# AI Coding Assistants - Amazon Q Developer (formerly CodeWhisperer)
+.aws/
+.codewhisperer/
+.amazonq/
+.aws-toolkit/
+
+# AI Coding Assistants - Tabnine
+.tabnine/
+tabnine_config.json
+
+# AI Coding Assistants - Kiro
+.kiro/
+.kiroignore
+kiro.config.json
+
+# AI Coding Assistants - Aider
+.aider/
+.aider.chat.history.md
+.aider.input.history
+.aider.tags.cache.v3/
+
+# AI Coding Assistants - Windsurf
+.windsurf/
+.windsurfignore
+
+# AI Coding Assistants - Replit Agent
+.replit
+.replitignore
+
+# AI Coding Assistants - Supermaven
+.supermaven/
+
+# AI Coding Assistants - Sourcegraph Cody
+.cody/
+
+# AI Coding Assistants - General
+.ai/
+.aiconfig
+ai-config.json
# Terraform
.terraform*
@@ -63,7 +134,7 @@ junit-reports/
# .env
ui/.env*
api/.env*
-.env.local
+mcp_server/.env*
# Coverage
.coverage*
@@ -78,3 +149,10 @@ _data/
# Claude
CLAUDE.md
+
+# MCP Server
+mcp_server/prowler_mcp_server/prowler_app/server.py
+mcp_server/prowler_mcp_server/prowler_app/utils/schema.yaml
+
+# Compliance report
+*.pdf
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 80c9ac250f..d4bb2435f1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,6 +6,7 @@ repos:
- id: check-merge-conflict
- id: check-yaml
args: ["--unsafe"]
+ exclude: prowler/config/llm_config.yaml
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000..c6a6027c18
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,110 @@
+# Repository Guidelines
+
+## How to Use This Guide
+
+- Start here for cross-project norms, Prowler is a monorepo with several components. Every component should have an `AGENTS.md` file that contains the guidelines for the agents in that component. The file is located beside the code you are touching (e.g. `api/AGENTS.md`, `ui/AGENTS.md`, `prowler/AGENTS.md`).
+- Follow the stricter rule when guidance conflicts; component docs override this file for their scope.
+- Keep instructions synchronized. When you add new workflows or scripts, update both, the relevant component `AGENTS.md` and this file if they apply broadly.
+
+## Project Overview
+
+Prowler is an open-source cloud security assessment tool that supports multiple cloud providers (AWS, Azure, GCP, Kubernetes, GitHub, M365, etc.). The project consists in a monorepo with the following main components:
+
+- **Prowler SDK**: Python SDK, includes the Prowler CLI, providers, services, checks, compliances, config, etc. (`prowler/`)
+- **Prowler API**: Django-based REST API backend (`api/`)
+- **Prowler UI**: Next.js frontend application (`ui/`)
+- **Prowler MCP Server**: Model Context Protocol server that gives access to the entire Prowler ecosystem for LLMs (`mcp_server/`)
+- **Prowler Dashboard**: Prowler CLI feature that allows to visualize the results of the scans in a simple dashboard (`dashboard/`)
+
+### Project Structure (Key Folders & Files)
+
+- `prowler/`: Main source code for Prowler SDK (CLI, providers, services, checks, compliances, config, etc.)
+- `api/`: Django-based REST API backend components
+- `ui/`: Next.js frontend application
+- `mcp_server/`: Model Context Protocol server that gives access to the entire Prowler ecosystem for LLMs
+- `dashboard/`: Prowler CLI feature that allows to visualize the results of the scans in a simple dashboard
+- `docs/`: Documentation
+- `examples/`: Example output formats for providers and scripts
+- `permissions/`: Permission-related files and policies
+- `contrib/`: Community-contributed scripts or modules
+- `tests/`: Prowler SDK test suite
+- `docker-compose.yml`: Docker compose file to run the Prowler App (API + UI) production environment
+- `docker-compose-dev.yml`: Docker compose file to run the Prowler App (API + UI) development environment
+- `pyproject.toml`: Poetry Prowler SDK project file
+- `.pre-commit-config.yaml`: Pre-commit hooks configuration
+- `Makefile`: Makefile to run the project
+- `LICENSE`: License file
+- `README.md`: README file
+- `CONTRIBUTING.md`: Contributing guide
+
+## Python Development
+
+Most of the code is written in Python, so the main files in the root are focused on Python code.
+
+### Poetry Dev Environment
+
+For developing in Python we recommend using `poetry` to manage the dependencies. The minimal version is `2.1.1`. So it is recommended to run all commands using `poetry run ...`.
+
+To install the core dependencies to develop it is needed to run `poetry install --with dev`.
+
+### Pre-commit hooks
+
+The project has pre-commit hooks to lint and format the code. They are installed by running `poetry run pre-commit install`.
+
+When commiting a change, the hooks will be run automatically. Some of them are:
+
+- Code formatting (black, isort)
+- Linting (flake8, pylint)
+- Security checks (bandit, safety, trufflehog)
+- YAML/JSON validation
+- Poetry lock file validation
+
+
+### Linting and Formatting
+
+We use the following tools to lint and format the code:
+
+- `flake8`: for linting the code
+- `black`: for formatting the code
+- `pylint`: for linting the code
+
+You can run all using the `make` command:
+```bash
+poetry run make lint
+poetry run make format
+```
+
+Or they will be run automatically when you commit your changes using pre-commit hooks.
+
+## Commit & Pull Request Guidelines
+
+For the commit messages and pull requests name follow the conventional-commit style.
+
+Befire creating a pull request, complete the checklist in `.github/pull_request_template.md`. Summaries should explain deployment impact, highlight review steps, and note changelog or permission updates. Run all relevant tests and linters before requesting review and link screenshots for UI or dashboard changes.
+
+### Conventional Commit Style
+
+The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of.
+
+The commit message should be structured as follows:
+
+```
+[optional scope]:
+
+[optional body]
+
+[optional footer(s)]
+```
+
+Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools
+
+#### Commit Types
+
+- **feat**: code change introuce new functionality to the application
+- **fix**: code change that solve a bug in the codebase
+- **docs**: documentation only changes
+- **chore**: changes related to the build process or auxiliary tools and libraries, that do not affect the application's functionality
+- **perf**: code change that improves performance
+- **refactor**: code change that neither fixes a bug nor adds a feature
+- **style**: changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
+- **test**: adding missing tests or correcting existing tests
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2dc954e9d9..f530feb99a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,4 +10,4 @@
Want some swag as appreciation for your contribution?
# Prowler Developer Guide
-https://docs.prowler.com/projects/prowler-open-source/en/latest/developer-guide/introduction/
+https://goto.prowler.com/devguide
diff --git a/Dockerfile b/Dockerfile
index 5884bda9f3..f71c53e008 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,6 +4,10 @@ LABEL maintainer="https://github.com/prowler-cloud/prowler"
LABEL org.opencontainers.image.source="https://github.com/prowler-cloud/prowler"
ARG POWERSHELL_VERSION=7.5.0
+ENV POWERSHELL_VERSION=${POWERSHELL_VERSION}
+
+ARG TRIVY_VERSION=0.66.0
+ENV TRIVY_VERSION=${TRIVY_VERSION}
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -25,6 +29,24 @@ RUN ARCH=$(uname -m) && \
ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && \
rm /tmp/powershell.tar.gz
+# Install Trivy for IaC scanning
+RUN ARCH=$(uname -m) && \
+ if [ "$ARCH" = "x86_64" ]; then \
+ TRIVY_ARCH="Linux-64bit" ; \
+ elif [ "$ARCH" = "aarch64" ]; then \
+ TRIVY_ARCH="Linux-ARM64" ; \
+ else \
+ echo "Unsupported architecture for Trivy: $ARCH" && exit 1 ; \
+ fi && \
+ wget --progress=dot:giga "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_${TRIVY_ARCH}.tar.gz" -O /tmp/trivy.tar.gz && \
+ tar zxf /tmp/trivy.tar.gz -C /tmp && \
+ mv /tmp/trivy /usr/local/bin/trivy && \
+ chmod +x /usr/local/bin/trivy && \
+ rm /tmp/trivy.tar.gz && \
+ # Create trivy cache directory with proper permissions
+ mkdir -p /tmp/.cache/trivy && \
+ chmod 777 /tmp/.cache/trivy
+
# Add prowler user
RUN addgroup --gid 1000 prowler && \
adduser --uid 1000 --gid 1000 --disabled-password --gecos "" prowler
diff --git a/Makefile b/Makefile
index ccd67c5a45..861c9cf7fe 100644
--- a/Makefile
+++ b/Makefile
@@ -45,3 +45,15 @@ pypi-upload: ## Upload package
help: ## Show this help.
@echo "Prowler Makefile"
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+##@ Build no cache
+build-no-cache-dev:
+ docker compose -f docker-compose-dev.yml build --no-cache api-dev worker-dev worker-beat
+
+##@ Development Environment
+run-api-dev: ## Start development environment with API, PostgreSQL, Valkey, and workers
+ docker compose -f docker-compose-dev.yml up api-dev postgres valkey worker-dev worker-beat
+
+##@ Development Environment
+build-and-run-api-dev: build-no-cache-dev run-api-dev
+
diff --git a/README.md b/README.md
index fce0fbdc48..25cc8f6abe 100644
--- a/README.md
+++ b/README.md
@@ -19,19 +19,16 @@
-
+
-
-
-
-
-
+
+
@@ -55,15 +52,11 @@ Prowler includes hundreds of built-in controls to ensure compliance with standar
- **National Security Standards:** ENS (Spanish National Security Scheme)
- **Custom Security Frameworks:** Tailored to your needs
-## Prowler CLI and Prowler Cloud
-
-Prowler offers a Command Line Interface (CLI), known as Prowler Open Source, and an additional service built on top of it, called Prowler Cloud.
-
## Prowler App
Prowler App is a web-based application that simplifies running Prowler across your cloud provider accounts. It provides a user-friendly interface to visualize the results and streamline your security assessments.
-
+
>For more details, refer to the [Prowler App Documentation](https://docs.prowler.com/projects/prowler-open-source/en/latest/#prowler-app-installation)
@@ -80,28 +73,38 @@ prowler
```console
prowler dashboard
```
-
+
# Prowler at a Glance
+> [!Tip]
+> For the most accurate and up-to-date information about checks, services, frameworks, and categories, visit [**Prowler Hub**](https://hub.prowler.com).
-| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) |
-|---|---|---|---|---|
-| AWS | 571 | 82 | 36 | 10 |
-| GCP | 79 | 13 | 10 | 3 |
-| Azure | 162 | 19 | 11 | 4 |
-| Kubernetes | 83 | 7 | 5 | 7 |
-| GitHub | 17 | 2 | 1 | 0 |
-| M365 | 70 | 7 | 3 | 2 |
-| NHN (Unofficial) | 6 | 2 | 1 | 0 |
+
+| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | Support | Interface |
+|---|---|---|---|---|---|---|
+| AWS | 576 | 82 | 39 | 10 | Official | UI, API, CLI |
+| GCP | 79 | 13 | 13 | 3 | Official | UI, API, CLI |
+| Azure | 162 | 19 | 13 | 4 | Official | UI, API, CLI |
+| Kubernetes | 83 | 7 | 5 | 7 | Official | UI, API, CLI |
+| GitHub | 17 | 2 | 1 | 0 | Official | Stable | UI, API, CLI |
+| M365 | 70 | 7 | 3 | 2 | Official | UI, API, CLI |
+| OCI | 51 | 13 | 1 | 10 | Official | UI, API, CLI |
+| IaC | [See `trivy` docs.](https://trivy.dev/latest/docs/coverage/iac/) | N/A | N/A | N/A | Official | UI, API, CLI |
+| MongoDB Atlas | 10 | 3 | 0 | 0 | Official | CLI, API |
+| LLM | [See `promptfoo` docs.](https://www.promptfoo.dev/docs/red-team/plugins/) | N/A | N/A | N/A | Official | CLI |
+| NHN | 6 | 2 | 1 | 0 | Unofficial | CLI |
> [!Note]
> The numbers in the table are updated periodically.
-> [!Tip]
-> For the most accurate and up-to-date information about checks, services, frameworks, and categories, visit [**Prowler Hub**](https://hub.prowler.com).
+
> [!Note]
-> Use the following commands to list Prowler's available checks, services, compliance frameworks, and categories: `prowler --list-checks`, `prowler --list-services`, `prowler --list-compliance` and `prowler --list-categories`.
+> Use the following commands to list Prowler's available checks, services, compliance frameworks, and categories:
+> - `prowler --list-checks`
+> - `prowler --list-services`
+> - `prowler --list-compliance`
+> - `prowler --list-categories`
# š» Installation
@@ -239,7 +242,7 @@ The following versions of Prowler CLI are available, depending on your requireme
The container images are available here:
- Prowler CLI:
- - [DockerHub](https://hub.docker.com/r/toniblyx/prowler/tags)
+ - [DockerHub](https://hub.docker.com/r/prowlercloud/prowler/tags)
- [AWS Public ECR](https://gallery.ecr.aws/prowler-cloud/prowler)
- Prowler App:
- [DockerHub - Prowler UI](https://hub.docker.com/r/prowlercloud/prowler-ui/tags)
@@ -274,7 +277,7 @@ python prowler-cli.py -v
- **Prowler API**: A backend service, developed with Django REST Framework, responsible for running Prowler scans and storing the generated results.
- **Prowler SDK**: A Python SDK designed to extend the functionality of the Prowler CLI for advanced capabilities.
-
+
## Prowler CLI
@@ -300,40 +303,12 @@ And many more environments.

-# Deprecations from v3
-
-## General
-- `Allowlist` now is called `Mutelist`.
-- The `--quiet` option has been deprecated. Use the `--status` flag to filter findings based on their status: PASS, FAIL, or MANUAL.
-- All findings with an `INFO` status have been reclassified as `MANUAL`.
-- The CSV output format is standardized across all providers.
-
-**Deprecated Output Formats**
-
-The following formats are now deprecated:
-- Native JSON has been replaced with JSON in [OCSF] v1.1.0 format, which is standardized across all providers (https://schema.ocsf.io/).
-
-## AWS
-
-**AWS Flag Deprecation**
-
-The flag --sts-endpoint-region has been deprecated due to the adoption of AWS STS regional tokens.
-
-**Sending FAIL Results to AWS Security Hub**
-
-- To send only FAILS to AWS Security Hub, use one of the following options: `--send-sh-only-fails` or `--security-hub --status FAIL`.
-
-
# š Documentation
-**Documentation Resources**
-
For installation instructions, usage details, tutorials, and the Developer Guide, visit https://docs.prowler.com/
# š License
-**Prowler License Information**
-
-Prowler is licensed under the Apache License 2.0, as indicated in each file within the repository. Obtaining a Copy of the License
+Prowler is licensed under the Apache License 2.0.
A copy of the License is available at
diff --git a/api/.env.example b/api/.env.example
index 76ea6de3d2..0be5388790 100644
--- a/api/.env.example
+++ b/api/.env.example
@@ -19,6 +19,8 @@ DJANGO_REFRESH_TOKEN_LIFETIME=1440
DJANGO_CACHE_MAX_AGE=3600
DJANGO_STALE_WHILE_REVALIDATE=60
DJANGO_SECRETS_ENCRYPTION_KEY=""
+# Throttle, two options: Empty means no throttle; or if desired use one in DRF format: https://www.django-rest-framework.org/api-guide/throttling/#setting-the-throttling-policy
+DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
# Decide whether to allow Django manage database table partitions
DJANGO_MANAGE_DB_PARTITIONS=[True|False]
DJANGO_CELERY_DEADLOCK_ATTEMPTS=5
diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md
index adc80ed8cf..ce5d8eed74 100644
--- a/api/CHANGELOG.md
+++ b/api/CHANGELOG.md
@@ -2,13 +2,112 @@
All notable changes to the **Prowler API** are documented in this file.
-## [1.12.0] (Prowler 5.11.0 - UNRELEASED)
+## [1.15.0] (Prowler UNRELEASED)
+
+### Added
+- IaC (Infrastructure as Code) provider support for remote repositories [(#8751)](https://github.com/prowler-cloud/prowler/pull/8751)
+- Extend `GET /api/v1/providers` with provider-type filters and optional pagination disable to support the new Overview filters [(#8975)](https://github.com/prowler-cloud/prowler/pull/8975)
+- New endpoint to retrieve the number of providers grouped by provider type [(#8975)](https://github.com/prowler-cloud/prowler/pull/8975)
+- Support for configuring multiple LLM providers [(#8772)](https://github.com/prowler-cloud/prowler/pull/8772)
+- Support C5 compliance framework for Azure provider [(#9081)](https://github.com/prowler-cloud/prowler/pull/9081)
+- Support for Oracle Cloud Infrastructure (OCI) provider [(#8927)](https://github.com/prowler-cloud/prowler/pull/8927)
+- Support muting findings based on simple rules with custom reason [(#9051)](https://github.com/prowler-cloud/prowler/pull/9051)
+- Support C5 compliance framework for the GCP provider [(#9097)](https://github.com/prowler-cloud/prowler/pull/9097)
+- Support for Amazon Bedrock and OpenAI compatible providers in Lighthouse AI [(#8957)](https://github.com/prowler-cloud/prowler/pull/8957)
+- Tenant-wide ThreatScore overview aggregation and snapshot persistence with backfill support [(#9148)](https://github.com/prowler-cloud/prowler/pull/9148)
+- Added `metadata`, `details`, and `partition` attributes to `/resources` endpoint & `details`, and `partition` to `/findings` endpoint [(#9098)](https://github.com/prowler-cloud/prowler/pull/9098)
+- Support for MongoDB Atlas provider [(#9167)](https://github.com/prowler-cloud/prowler/pull/9167)
+- Enhanced compliance overview endpoint with provider filtering and latest scan aggregation [(#9244)](https://github.com/prowler-cloud/prowler/pull/9244)
+
+### Changed
+- Optimized database write queries for scan related tasks [(#9190)](https://github.com/prowler-cloud/prowler/pull/9190)
+- Date filters are now optional for `GET /api/v1/overviews/services` endpoint; returns latest scan data by default [(#9248)](https://github.com/prowler-cloud/prowler/pull/9248)
+
+### Fixed
+- Scans no longer fail when findings have UIDs exceeding 300 characters; such findings are now skipped with detailed logging [(#9246)](https://github.com/prowler-cloud/prowler/pull/9246)
+
+### Security
+- Django updated to the latest 5.1 security release, 5.1.14, due to problems with potential [SQL injection](https://github.com/prowler-cloud/prowler/security/dependabot/113) and [denial-of-service vulnerability](https://github.com/prowler-cloud/prowler/security/dependabot/114) [(#9176)](https://github.com/prowler-cloud/prowler/pull/9176)
+
+---
+
+## [1.14.2] (Prowler 5.13.2)
+
+### Fixed
+- Update unique constraint for `Provider` model to exclude soft-deleted entries, resolving duplicate errors when re-deleting providers [(#9054)](https://github.com/prowler-cloud/prowler/pull/9054)
+- Remove compliance generation for providers without compliance frameworks [(#9208)](https://github.com/prowler-cloud/prowler/pull/9208)
+
+## [1.14.1] (Prowler 5.13.1)
+
+### Fixed
+- `/api/v1/overviews/providers` collapses data by provider type so the UI receives a single aggregated record per cloud family even when multiple accounts exist [(#9053)](https://github.com/prowler-cloud/prowler/pull/9053)
+- Added retry logic to database transactions to handle Aurora read replica connection failures during scale-down events [(#9064)](https://github.com/prowler-cloud/prowler/pull/9064)
+- Security Hub integrations stop failing when they read relationships via the replica by allowing replica relations and saving updates through the primary [(#9080)](https://github.com/prowler-cloud/prowler/pull/9080)
+
+---
+
+## [1.14.0] (Prowler 5.13.0)
+
+### Added
+- Default JWT keys are generated and stored if they are missing from configuration [(#8655)](https://github.com/prowler-cloud/prowler/pull/8655)
+- `compliance_name` for each compliance [(#7920)](https://github.com/prowler-cloud/prowler/pull/7920)
+- Support C5 compliance framework for the AWS provider [(#8830)](https://github.com/prowler-cloud/prowler/pull/8830)
+- Support for M365 Certificate authentication [(#8538)](https://github.com/prowler-cloud/prowler/pull/8538)
+- API Key support [(#8805)](https://github.com/prowler-cloud/prowler/pull/8805)
+- SAML role mapping protection for single-admin tenants to prevent accidental lockout [(#8882)](https://github.com/prowler-cloud/prowler/pull/8882)
+- Support for `passed_findings` and `total_findings` fields in compliance requirement overview for accurate Prowler ThreatScore calculation [(#8582)](https://github.com/prowler-cloud/prowler/pull/8582)
+- PDF reporting for Prowler ThreatScore [(#8867)](https://github.com/prowler-cloud/prowler/pull/8867)
+- Database read replica support [(#8869)](https://github.com/prowler-cloud/prowler/pull/8869)
+- Support Common Cloud Controls for AWS, Azure and GCP [(#8000)](https://github.com/prowler-cloud/prowler/pull/8000)
+- Add `provider_id__in` filter support to findings and findings severity overview endpoints [(#8951)](https://github.com/prowler-cloud/prowler/pull/8951)
+
+### Changed
+- Now the MANAGE_ACCOUNT permission is required to modify or read user permissions instead of MANAGE_USERS [(#8281)](https://github.com/prowler-cloud/prowler/pull/8281)
+- Now at least one user with MANAGE_ACCOUNT permission is required in the tenant [(#8729)](https://github.com/prowler-cloud/prowler/pull/8729)
+
+### Security
+- Django updated to the latest 5.1 security release, 5.1.13, due to problems with potential [SQL injection](https://github.com/prowler-cloud/prowler/security/dependabot/104) and [directory traversals](https://github.com/prowler-cloud/prowler/security/dependabot/103) [(#8842)](https://github.com/prowler-cloud/prowler/pull/8842)
+
+---
+
+## [1.13.2] (Prowler 5.12.3)
+
+### Fixed
+- 500 error when deleting user [(#8731)](https://github.com/prowler-cloud/prowler/pull/8731)
+
+---
+
+## [1.13.1] (Prowler 5.12.2)
+
+### Changed
+- Renamed compliance overview task queue to `compliance` [(#8755)](https://github.com/prowler-cloud/prowler/pull/8755)
+
+### Security
+- Django updated to the latest 5.1 security release, 5.1.12, due to [problems](https://www.djangoproject.com/weblog/2025/sep/03/security-releases/) with potential SQL injection in FilteredRelation column aliases [(#8693)](https://github.com/prowler-cloud/prowler/pull/8693)
+
+---
+
+## [1.13.0] (Prowler 5.12.0)
+
+### Added
+- Integration with JIRA, enabling sending findings to a JIRA project [(#8622)](https://github.com/prowler-cloud/prowler/pull/8622), [(#8637)](https://github.com/prowler-cloud/prowler/pull/8637)
+- `GET /overviews/findings_severity` now supports `filter[status]` and `filter[status__in]` to aggregate by specific statuses (`FAIL`, `PASS`)[(#8186)](https://github.com/prowler-cloud/prowler/pull/8186)
+- Throttling options for `/api/v1/tokens` using the `DJANGO_THROTTLE_TOKEN_OBTAIN` environment variable [(#8647)](https://github.com/prowler-cloud/prowler/pull/8647)
+
+---
+
+## [1.12.0] (Prowler 5.11.0)
### Added
- Lighthouse support for OpenAI GPT-5 [(#8527)](https://github.com/prowler-cloud/prowler/pull/8527)
- Integration with Amazon Security Hub, enabling sending findings to Security Hub [(#8365)](https://github.com/prowler-cloud/prowler/pull/8365)
- Generate ASFF output for AWS providers with SecurityHub integration enabled [(#8569)](https://github.com/prowler-cloud/prowler/pull/8569)
+### Fixed
+- GitHub provider always scans user instead of organization when using provider UID [(#8587)](https://github.com/prowler-cloud/prowler/pull/8587)
+
+---
+
## [1.11.0] (Prowler 5.10.0)
### Added
diff --git a/api/Dockerfile b/api/Dockerfile
index a3cfb21782..2d7883a957 100644
--- a/api/Dockerfile
+++ b/api/Dockerfile
@@ -5,6 +5,9 @@ LABEL maintainer="https://github.com/prowler-cloud/api"
ARG POWERSHELL_VERSION=7.5.0
ENV POWERSHELL_VERSION=${POWERSHELL_VERSION}
+ARG TRIVY_VERSION=0.66.0
+ENV TRIVY_VERSION=${TRIVY_VERSION}
+
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
@@ -36,6 +39,24 @@ RUN ARCH=$(uname -m) && \
ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && \
rm /tmp/powershell.tar.gz
+# Install Trivy for IaC scanning
+RUN ARCH=$(uname -m) && \
+ if [ "$ARCH" = "x86_64" ]; then \
+ TRIVY_ARCH="Linux-64bit" ; \
+ elif [ "$ARCH" = "aarch64" ]; then \
+ TRIVY_ARCH="Linux-ARM64" ; \
+ else \
+ echo "Unsupported architecture for Trivy: $ARCH" && exit 1 ; \
+ fi && \
+ wget --progress=dot:giga "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_${TRIVY_ARCH}.tar.gz" -O /tmp/trivy.tar.gz && \
+ tar zxf /tmp/trivy.tar.gz -C /tmp && \
+ mv /tmp/trivy /usr/local/bin/trivy && \
+ chmod +x /usr/local/bin/trivy && \
+ rm /tmp/trivy.tar.gz && \
+ # Create trivy cache directory with proper permissions
+ mkdir -p /tmp/.cache/trivy && \
+ chmod 777 /tmp/.cache/trivy
+
# Add prowler user
RUN addgroup --gid 1000 prowler && \
adduser --uid 1000 --gid 1000 --disabled-password --gecos "" prowler
diff --git a/api/README.md b/api/README.md
index ba8896ff35..60a2669718 100644
--- a/api/README.md
+++ b/api/README.md
@@ -18,7 +18,11 @@ Valkey exposes a Redis 7.2 compliant API. Any service that exposes the Redis API
# Modify environment variables
-Under the root path of the project, you can find a file called `.env.example`. This file shows all the environment variables that the project uses. You *must* create a new file called `.env` and set the values for the variables.
+Under the root path of the project, you can find a file called `.env`. This file shows all the environment variables that the project uses. You should review it and set the values for the variables you want to change.
+
+If you donāt set `DJANGO_TOKEN_SIGNING_KEY` or `DJANGO_TOKEN_VERIFYING_KEY`, the API will generate them at `~/.config/prowler-api/` with `0600` and `0644` permissions; back up these files to persist identity across redeploys.
+
+**Important note**: Every Prowler version (or repository branches and tags) could have different variables set in its `.env` file. Please use the `.env` file that corresponds with each version.
## Local deployment
Keep in mind if you export the `.env` file to use it with local deployment that you will have to do it within the context of the Poetry interpreter, not before. Otherwise, variables will not be loaded properly.
diff --git a/api/docker-entrypoint.sh b/api/docker-entrypoint.sh
index 5669de6788..f9b19e04d0 100755
--- a/api/docker-entrypoint.sh
+++ b/api/docker-entrypoint.sh
@@ -32,7 +32,7 @@ start_prod_server() {
start_worker() {
echo "Starting the worker..."
- poetry run python -m celery -A config.celery worker -l "${DJANGO_LOGGING_LEVEL:-info}" -Q celery,scans,scan-reports,deletion,backfill,overview,integrations -E --max-tasks-per-child 1
+ poetry run python -m celery -A config.celery worker -l "${DJANGO_LOGGING_LEVEL:-info}" -Q celery,scans,scan-reports,deletion,backfill,overview,integrations,compliance -E --max-tasks-per-child 1
}
start_worker_beat() {
diff --git a/api/poetry.lock b/api/poetry.lock
index 5171644ab1..332d4d9f73 100644
--- a/api/poetry.lock
+++ b/api/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
[[package]]
name = "about-time"
@@ -273,14 +273,14 @@ tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" a
[[package]]
name = "authlib"
-version = "1.6.1"
+version = "1.6.5"
description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients."
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
- {file = "authlib-1.6.1-py2.py3-none-any.whl", hash = "sha256:e9d2031c34c6309373ab845afc24168fe9e93dc52d252631f52642f21f5ed06e"},
- {file = "authlib-1.6.1.tar.gz", hash = "sha256:4dffdbb1460ba6ec8c17981a4c67af7d8af131231b5a36a88a1e8c80c111cdfd"},
+ {file = "authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a"},
+ {file = "authlib-1.6.5.tar.gz", hash = "sha256:6aaf9c79b7cc96c900f0b284061691c5d4e61221640a948fe690b556a6d6d10b"},
]
[package.dependencies]
@@ -383,6 +383,24 @@ cryptography = ">=2.1.4"
isodate = ">=0.6.1"
typing-extensions = ">=4.0.1"
+[[package]]
+name = "azure-mgmt-apimanagement"
+version = "5.0.0"
+description = "Microsoft Azure API Management Client Library for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "azure_mgmt_apimanagement-5.0.0-py3-none-any.whl", hash = "sha256:b88c42a392333b60722fb86f15d092dfc19a8d67510dccd15c217381dff4e6ec"},
+ {file = "azure_mgmt_apimanagement-5.0.0.tar.gz", hash = "sha256:0ab7fe17e70fe3154cd840ff47d19d7a4610217003eaa7c21acf3511a6e57999"},
+]
+
+[package.dependencies]
+azure-common = ">=1.1"
+azure-mgmt-core = ">=1.3.2"
+isodate = ">=0.6.1"
+typing-extensions = ">=4.6.0"
+
[[package]]
name = "azure-mgmt-applicationinsights"
version = "4.1.0"
@@ -540,6 +558,23 @@ azure-mgmt-core = ">=1.3.2"
isodate = ">=0.6.1"
typing-extensions = ">=4.6.0"
+[[package]]
+name = "azure-mgmt-loganalytics"
+version = "12.0.0"
+description = "Microsoft Azure Log Analytics Management Client Library for Python"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "azure-mgmt-loganalytics-12.0.0.zip", hash = "sha256:da128a7e0291be7fa2063848df92a9180cf5c16d42adc09d2bc2efd711536bfb"},
+ {file = "azure_mgmt_loganalytics-12.0.0-py2.py3-none-any.whl", hash = "sha256:75ac1d47dd81179905c40765be8834643d8994acff31056ddc1863017f3faa02"},
+]
+
+[package.dependencies]
+azure-common = ">=1.1,<2.0"
+azure-mgmt-core = ">=1.2.0,<2.0.0"
+msrest = ">=0.6.21"
+
[[package]]
name = "azure-mgmt-monitor"
version = "6.0.2"
@@ -750,6 +785,23 @@ azure-mgmt-core = ">=1.3.2"
isodate = ">=0.6.1"
typing-extensions = ">=4.6.0"
+[[package]]
+name = "azure-monitor-query"
+version = "2.0.0"
+description = "Microsoft Corporation Azure Monitor Query Client Library for Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "azure_monitor_query-2.0.0-py3-none-any.whl", hash = "sha256:8f52d581271d785e12f49cd5aaa144b8910fb843db2373855a7ef94c7fc462ea"},
+ {file = "azure_monitor_query-2.0.0.tar.gz", hash = "sha256:7b05f2fcac4fb67fc9f77a7d4c5d98a0f3099fb73b57c69ec1b080773994671b"},
+]
+
+[package.dependencies]
+azure-core = ">=1.30.0"
+isodate = ">=0.6.1"
+typing-extensions = ">=4.6.0"
+
[[package]]
name = "azure-storage-blob"
version = "12.24.1"
@@ -1204,6 +1256,98 @@ files = [
{file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"},
]
+[[package]]
+name = "contourpy"
+version = "1.3.3"
+description = "Python library for calculating contours of 2D quadrilateral grids"
+optional = false
+python-versions = ">=3.11"
+groups = ["main"]
+files = [
+ {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"},
+ {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"},
+ {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7"},
+ {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1"},
+ {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a"},
+ {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db"},
+ {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620"},
+ {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f"},
+ {file = "contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff"},
+ {file = "contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42"},
+ {file = "contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470"},
+ {file = "contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb"},
+ {file = "contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6"},
+ {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7"},
+ {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8"},
+ {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea"},
+ {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1"},
+ {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7"},
+ {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411"},
+ {file = "contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69"},
+ {file = "contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b"},
+ {file = "contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc"},
+ {file = "contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5"},
+ {file = "contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1"},
+ {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286"},
+ {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5"},
+ {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67"},
+ {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9"},
+ {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659"},
+ {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7"},
+ {file = "contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d"},
+ {file = "contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263"},
+ {file = "contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9"},
+ {file = "contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d"},
+ {file = "contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216"},
+ {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae"},
+ {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20"},
+ {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99"},
+ {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b"},
+ {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a"},
+ {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e"},
+ {file = "contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3"},
+ {file = "contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8"},
+ {file = "contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301"},
+ {file = "contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a"},
+ {file = "contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77"},
+ {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5"},
+ {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4"},
+ {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36"},
+ {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3"},
+ {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b"},
+ {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36"},
+ {file = "contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d"},
+ {file = "contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd"},
+ {file = "contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339"},
+ {file = "contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772"},
+ {file = "contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77"},
+ {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13"},
+ {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe"},
+ {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f"},
+ {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0"},
+ {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4"},
+ {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f"},
+ {file = "contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae"},
+ {file = "contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc"},
+ {file = "contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b"},
+ {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497"},
+ {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8"},
+ {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e"},
+ {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989"},
+ {file = "contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77"},
+ {file = "contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880"},
+]
+
+[package.dependencies]
+numpy = ">=1.25"
+
+[package.extras]
+bokeh = ["bokeh", "selenium"]
+docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"]
+mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.17.0)", "types-Pillow"]
+test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
+test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
+
[[package]]
name = "coverage"
version = "7.5.4"
@@ -1338,6 +1482,22 @@ ssh = ["bcrypt (>=3.1.5)"]
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
test-randomorder = ["pytest-randomly"]
+[[package]]
+name = "cycler"
+version = "0.12.1"
+description = "Composable style cycles"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
+ {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
+]
+
+[package.extras]
+docs = ["ipython", "matplotlib", "numpydoc", "sphinx"]
+tests = ["pytest", "pytest-cov", "pytest-xdist"]
+
[[package]]
name = "dash"
version = "3.1.1"
@@ -1511,14 +1671,14 @@ with-social = ["django-allauth[socialaccount] (>=64.0.0)"]
[[package]]
name = "django"
-version = "5.1.10"
+version = "5.1.14"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
python-versions = ">=3.10"
groups = ["main", "dev"]
files = [
- {file = "django-5.1.10-py3-none-any.whl", hash = "sha256:19c9b771e9cf4de91101861aadd2daaa159bcf10698ca909c5755c88e70ccb84"},
- {file = "django-5.1.10.tar.gz", hash = "sha256:73e5d191421d177803dbd5495d94bc7d06d156df9561f4eea9e11b4994c07137"},
+ {file = "django-5.1.14-py3-none-any.whl", hash = "sha256:2a4b9c20404fd1bf50aaaa5542a19d860594cba1354f688f642feb271b91df27"},
+ {file = "django-5.1.14.tar.gz", hash = "sha256:b98409fb31fdd6e8c3a6ba2eef3415cc5c0020057b43b21ba7af6eff5f014831"},
]
[package.dependencies]
@@ -1872,6 +2032,27 @@ files = [
Django = ">=4.2"
djangorestframework = ">=3.15.0"
+[[package]]
+name = "drf-simple-apikey"
+version = "2.2.1"
+description = "API Key authentication and permissions for Django REST."
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "drf_simple_apikey-2.2.1-py2.py3-none-any.whl", hash = "sha256:2a60b35676d14f907c47dee179dd0fa7425a84c34d6ff5b48d08d3b87ff32809"},
+ {file = "drf_simple_apikey-2.2.1.tar.gz", hash = "sha256:e5a52804bbac12c8db80c10a3d51a8514fc59fc8385b5e751099a2bc944ad25d"},
+]
+
+[package.dependencies]
+cryptography = ">=38.0.4"
+django = ">=4.2"
+djangorestframework = ">=3.14.0"
+
+[package.extras]
+test = ["coverage", "pytest", "pytest-django"]
+tooling = ["black (==22.3.0)", "bump2version", "pylint"]
+
[[package]]
name = "drf-spectacular"
version = "0.27.2"
@@ -2047,6 +2228,87 @@ werkzeug = ">=3.1.0"
async = ["asgiref (>=3.2)"]
dotenv = ["python-dotenv"]
+[[package]]
+name = "fonttools"
+version = "4.60.1"
+description = "Tools to manipulate font files"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28"},
+ {file = "fonttools-4.60.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15"},
+ {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c"},
+ {file = "fonttools-4.60.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea"},
+ {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652"},
+ {file = "fonttools-4.60.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a"},
+ {file = "fonttools-4.60.1-cp310-cp310-win32.whl", hash = "sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce"},
+ {file = "fonttools-4.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038"},
+ {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f"},
+ {file = "fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2"},
+ {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914"},
+ {file = "fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1"},
+ {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d"},
+ {file = "fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa"},
+ {file = "fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258"},
+ {file = "fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf"},
+ {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc"},
+ {file = "fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877"},
+ {file = "fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c"},
+ {file = "fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401"},
+ {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903"},
+ {file = "fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed"},
+ {file = "fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6"},
+ {file = "fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383"},
+ {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb"},
+ {file = "fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4"},
+ {file = "fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c"},
+ {file = "fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77"},
+ {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199"},
+ {file = "fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c"},
+ {file = "fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272"},
+ {file = "fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac"},
+ {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3"},
+ {file = "fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85"},
+ {file = "fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537"},
+ {file = "fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003"},
+ {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08"},
+ {file = "fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99"},
+ {file = "fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6"},
+ {file = "fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987"},
+ {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299"},
+ {file = "fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01"},
+ {file = "fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801"},
+ {file = "fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc"},
+ {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc"},
+ {file = "fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed"},
+ {file = "fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259"},
+ {file = "fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c"},
+ {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:122e1a8ada290423c493491d002f622b1992b1ab0b488c68e31c413390dc7eb2"},
+ {file = "fonttools-4.60.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a140761c4ff63d0cb9256ac752f230460ee225ccef4ad8f68affc723c88e2036"},
+ {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eae96373e4b7c9e45d099d7a523444e3554360927225c1cdae221a58a45b856"},
+ {file = "fonttools-4.60.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:596ecaca36367027d525b3b426d8a8208169d09edcf8c7506aceb3a38bfb55c7"},
+ {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ee06fc57512144d8b0445194c2da9f190f61ad51e230f14836286470c99f854"},
+ {file = "fonttools-4.60.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b42d86938e8dda1cd9a1a87a6d82f1818eaf933348429653559a458d027446da"},
+ {file = "fonttools-4.60.1-cp39-cp39-win32.whl", hash = "sha256:8b4eb332f9501cb1cd3d4d099374a1e1306783ff95489a1026bde9eb02ccc34a"},
+ {file = "fonttools-4.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:7473a8ed9ed09aeaa191301244a5a9dbe46fe0bf54f9d6cd21d83044c3321217"},
+ {file = "fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb"},
+ {file = "fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9"},
+]
+
+[package.extras]
+all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"]
+graphite = ["lz4 (>=1.7.4.2)"]
+interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""]
+lxml = ["lxml (>=4.0)"]
+pathops = ["skia-pathops (>=0.5.0)"]
+plot = ["matplotlib"]
+repacker = ["uharfbuzz (>=0.23.0)"]
+symfont = ["sympy"]
+type1 = ["xattr ; sys_platform == \"darwin\""]
+unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
+woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
+
[[package]]
name = "freezegun"
version = "1.5.1"
@@ -2714,6 +2976,117 @@ files = [
[package.dependencies]
referencing = ">=0.31.0"
+[[package]]
+name = "kiwisolver"
+version = "1.4.9"
+description = "A fast implementation of the Cassowary constraint solver"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611"},
+ {file = "kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2"},
+ {file = "kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54"},
+ {file = "kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d"},
+ {file = "kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07"},
+ {file = "kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7"},
+ {file = "kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891"},
+ {file = "kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32"},
+ {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527"},
+ {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771"},
+ {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e"},
+ {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9"},
+ {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb"},
+ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5"},
+ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa"},
+ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2"},
+ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f"},
+ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1"},
+ {file = "kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d"},
+]
+
[[package]]
name = "kombu"
version = "5.5.4"
@@ -2933,6 +3306,22 @@ html5 = ["html5lib"]
htmlsoup = ["BeautifulSoup4"]
source = ["Cython (>=3.0.11,<3.1.0)"]
+[[package]]
+name = "markdown"
+version = "3.9"
+description = "Python implementation of John Gruber's Markdown."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280"},
+ {file = "markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a"},
+]
+
+[package.extras]
+docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
+testing = ["coverage", "pyyaml"]
+
[[package]]
name = "markdown-it-py"
version = "4.0.0"
@@ -3048,6 +3437,85 @@ dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"]
docs = ["autodocsumm (==0.2.14)", "furo (==2024.8.6)", "sphinx (==8.1.3)", "sphinx-copybutton (==0.5.2)", "sphinx-issues (==5.0.0)", "sphinxext-opengraph (==0.9.1)"]
tests = ["pytest", "simplejson"]
+[[package]]
+name = "matplotlib"
+version = "3.10.6"
+description = "Python plotting package"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "matplotlib-3.10.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bc7316c306d97463a9866b89d5cc217824e799fa0de346c8f68f4f3d27c8693d"},
+ {file = "matplotlib-3.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d00932b0d160ef03f59f9c0e16d1e3ac89646f7785165ce6ad40c842db16cc2e"},
+ {file = "matplotlib-3.10.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fa4c43d6bfdbfec09c733bca8667de11bfa4970e8324c471f3a3632a0301c15"},
+ {file = "matplotlib-3.10.6-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea117a9c1627acaa04dbf36265691921b999cbf515a015298e54e1a12c3af837"},
+ {file = "matplotlib-3.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08fc803293b4e1694ee325896030de97f74c141ccff0be886bb5915269247676"},
+ {file = "matplotlib-3.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:2adf92d9b7527fbfb8818e050260f0ebaa460f79d61546374ce73506c9421d09"},
+ {file = "matplotlib-3.10.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:905b60d1cb0ee604ce65b297b61cf8be9f4e6cfecf95a3fe1c388b5266bc8f4f"},
+ {file = "matplotlib-3.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bac38d816637343e53d7185d0c66677ff30ffb131044a81898b5792c956ba76"},
+ {file = "matplotlib-3.10.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:942a8de2b5bfff1de31d95722f702e2966b8a7e31f4e68f7cd963c7cd8861cf6"},
+ {file = "matplotlib-3.10.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3276c85370bc0dfca051ec65c5817d1e0f8f5ce1b7787528ec8ed2d524bbc2f"},
+ {file = "matplotlib-3.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9df5851b219225731f564e4b9e7f2ac1e13c9e6481f941b5631a0f8e2d9387ce"},
+ {file = "matplotlib-3.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:abb5d9478625dd9c9eb51a06d39aae71eda749ae9b3138afb23eb38824026c7e"},
+ {file = "matplotlib-3.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:886f989ccfae63659183173bb3fced7fd65e9eb793c3cc21c273add368536951"},
+ {file = "matplotlib-3.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31ca662df6a80bd426f871105fdd69db7543e28e73a9f2afe80de7e531eb2347"},
+ {file = "matplotlib-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1678bb61d897bb4ac4757b5ecfb02bfb3fddf7f808000fb81e09c510712fda75"},
+ {file = "matplotlib-3.10.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:56cd2d20842f58c03d2d6e6c1f1cf5548ad6f66b91e1e48f814e4fb5abd1cb95"},
+ {file = "matplotlib-3.10.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:662df55604a2f9a45435566d6e2660e41efe83cd94f4288dfbf1e6d1eae4b0bb"},
+ {file = "matplotlib-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08f141d55148cd1fc870c3387d70ca4df16dee10e909b3b038782bd4bda6ea07"},
+ {file = "matplotlib-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:590f5925c2d650b5c9d813c5b3b5fc53f2929c3f8ef463e4ecfa7e052044fb2b"},
+ {file = "matplotlib-3.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:f44c8d264a71609c79a78d50349e724f5d5fc3684ead7c2a473665ee63d868aa"},
+ {file = "matplotlib-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:819e409653c1106c8deaf62e6de6b8611449c2cd9939acb0d7d4e57a3d95cc7a"},
+ {file = "matplotlib-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59c8ac8382fefb9cb71308dde16a7c487432f5255d8f1fd32473523abecfecdf"},
+ {file = "matplotlib-3.10.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84e82d9e0fd70c70bc55739defbd8055c54300750cbacf4740c9673a24d6933a"},
+ {file = "matplotlib-3.10.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25f7a3eb42d6c1c56e89eacd495661fc815ffc08d9da750bca766771c0fd9110"},
+ {file = "matplotlib-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9c862d91ec0b7842920a4cfdaaec29662195301914ea54c33e01f1a28d014b2"},
+ {file = "matplotlib-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:1b53bd6337eba483e2e7d29c5ab10eee644bc3a2491ec67cc55f7b44583ffb18"},
+ {file = "matplotlib-3.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:cbd5eb50b7058b2892ce45c2f4e92557f395c9991f5c886d1bb74a1582e70fd6"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:acc86dd6e0e695c095001a7fccff158c49e45e0758fdf5dcdbb0103318b59c9f"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e228cd2ffb8f88b7d0b29e37f68ca9aaf83e33821f24a5ccc4f082dd8396bc27"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:658bc91894adeab669cf4bb4a186d049948262987e80f0857216387d7435d833"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8913b7474f6dd83ac444c9459c91f7f0f2859e839f41d642691b104e0af056aa"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:091cea22e059b89f6d7d1a18e2c33a7376c26eee60e401d92a4d6726c4e12706"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:491e25e02a23d7207629d942c666924a6b61e007a48177fdd231a0097b7f507e"},
+ {file = "matplotlib-3.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3d80d60d4e54cda462e2cd9a086d85cd9f20943ead92f575ce86885a43a565d5"},
+ {file = "matplotlib-3.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:70aaf890ce1d0efd482df969b28a5b30ea0b891224bb315810a3940f67182899"},
+ {file = "matplotlib-3.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1565aae810ab79cb72e402b22facfa6501365e73ebab70a0fdfb98488d2c3c0c"},
+ {file = "matplotlib-3.10.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3b23315a01981689aa4e1a179dbf6ef9fbd17143c3eea77548c2ecfb0499438"},
+ {file = "matplotlib-3.10.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30fdd37edf41a4e6785f9b37969de57aea770696cb637d9946eb37470c94a453"},
+ {file = "matplotlib-3.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bc31e693da1c08012c764b053e702c1855378e04102238e6a5ee6a7117c53a47"},
+ {file = "matplotlib-3.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:05be9bdaa8b242bc6ff96330d18c52f1fc59c6fb3a4dd411d953d67e7e1baf98"},
+ {file = "matplotlib-3.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:f56a0d1ab05d34c628592435781d185cd99630bdfd76822cd686fb5a0aecd43a"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:94f0b4cacb23763b64b5dace50d5b7bfe98710fed5f0cef5c08135a03399d98b"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cc332891306b9fb39462673d8225d1b824c89783fee82840a709f96714f17a5c"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1d607b3fb1590deb04b69f02ea1d53ed0b0bf75b2b1a5745f269afcbd3cdd3"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:376a624a218116461696b27b2bbf7a8945053e6d799f6502fc03226d077807bf"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:83847b47f6524c34b4f2d3ce726bb0541c48c8e7692729865c3df75bfa0f495a"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c7e0518e0d223683532a07f4b512e2e0729b62674f1b3a1a69869f98e6b1c7e3"},
+ {file = "matplotlib-3.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:4dd83e029f5b4801eeb87c64efd80e732452781c16a9cf7415b7b63ec8f374d7"},
+ {file = "matplotlib-3.10.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:13fcd07ccf17e354398358e0307a1f53f5325dca22982556ddb9c52837b5af41"},
+ {file = "matplotlib-3.10.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:470fc846d59d1406e34fa4c32ba371039cd12c2fe86801159a965956f2575bd1"},
+ {file = "matplotlib-3.10.6-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7173f8551b88f4ef810a94adae3128c2530e0d07529f7141be7f8d8c365f051"},
+ {file = "matplotlib-3.10.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f2d684c3204fa62421bbf770ddfebc6b50130f9cad65531eeba19236d73bb488"},
+ {file = "matplotlib-3.10.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6f4a69196e663a41d12a728fab8751177215357906436804217d6d9cf0d4d6cf"},
+ {file = "matplotlib-3.10.6-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d6ca6ef03dfd269f4ead566ec6f3fb9becf8dab146fb999022ed85ee9f6b3eb"},
+ {file = "matplotlib-3.10.6.tar.gz", hash = "sha256:ec01b645840dd1996df21ee37f208cd8ba57644779fa20464010638013d3203c"},
+]
+
+[package.dependencies]
+contourpy = ">=1.0.1"
+cycler = ">=0.10"
+fonttools = ">=4.22.0"
+kiwisolver = ">=1.3.1"
+numpy = ">=1.23"
+packaging = ">=20.0"
+pillow = ">=8"
+pyparsing = ">=2.3.1"
+python-dateutil = ">=2.7"
+
+[package.extras]
+dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"]
+
[[package]]
name = "mccabe"
version = "0.7.0"
@@ -3768,6 +4236,131 @@ files = [
[package.dependencies]
setuptools = "*"
+[[package]]
+name = "pillow"
+version = "11.3.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
+ {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
+ {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"},
+ {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"},
+ {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"},
+ {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"},
+ {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"},
+ {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"},
+ {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"},
+ {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"},
+ {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"},
+ {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"},
+ {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"},
+ {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"},
+ {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"},
+ {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"},
+ {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"},
+ {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"},
+ {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"},
+ {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"},
+ {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"},
+ {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"},
+ {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"},
+ {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"},
+ {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"},
+ {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"},
+ {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"},
+ {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"},
+ {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"},
+ {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"},
+ {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"},
+ {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"},
+ {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"},
+ {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"},
+ {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"},
+ {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"},
+ {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"},
+ {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"},
+ {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"},
+ {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"},
+ {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"},
+ {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"},
+ {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"},
+ {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"},
+ {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"},
+ {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"},
+ {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"},
+ {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"},
+ {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"},
+ {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"},
+ {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"},
+ {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"},
+ {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"},
+ {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"},
+ {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"},
+ {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"},
+ {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"},
+ {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"},
+ {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"},
+ {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"},
+ {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"},
+ {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"},
+ {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"},
+ {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"},
+ {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"},
+ {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"},
+ {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"},
+ {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"},
+ {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"},
+ {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"},
+ {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"},
+ {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"},
+ {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"},
+ {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"},
+ {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"},
+ {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"},
+ {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"},
+ {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"},
+ {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"},
+ {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"},
+ {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"},
+ {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"},
+ {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"},
+ {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"},
+ {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"},
+ {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"},
+ {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"},
+ {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"},
+ {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"},
+ {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"},
+ {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"},
+ {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"},
+ {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"},
+ {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
+fpx = ["olefile"]
+mic = ["olefile"]
+test-arrow = ["pyarrow"]
+tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
+typing = ["typing-extensions ; python_version < \"3.10\""]
+xmp = ["defusedxml"]
+
[[package]]
name = "platformdirs"
version = "4.3.8"
@@ -3987,7 +4580,7 @@ files = [
[[package]]
name = "prowler"
-version = "5.11.0"
+version = "5.13.0"
description = "Prowler is an Open Source security tool to perform AWS, GCP and Azure security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness. It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks."
optional = false
python-versions = ">3.9.1,<3.13"
@@ -4000,6 +4593,7 @@ alive-progress = "3.3.0"
awsipranges = "0.3.3"
azure-identity = "1.21.0"
azure-keyvault-keys = "4.10.0"
+azure-mgmt-apimanagement = "5.0.0"
azure-mgmt-applicationinsights = "4.1.0"
azure-mgmt-authorization = "4.0.0"
azure-mgmt-compute = "34.0.0"
@@ -4008,6 +4602,7 @@ azure-mgmt-containerservice = "34.1.0"
azure-mgmt-cosmosdb = "9.7.0"
azure-mgmt-databricks = "2.0.0"
azure-mgmt-keyvault = "10.3.1"
+azure-mgmt-loganalytics = "12.0.0"
azure-mgmt-monitor = "6.0.2"
azure-mgmt-network = "28.1.0"
azure-mgmt-rdbms = "10.1.0"
@@ -4020,6 +4615,7 @@ azure-mgmt-sql = "3.0.1"
azure-mgmt-storage = "22.1.1"
azure-mgmt-subscription = "3.1.1"
azure-mgmt-web = "8.0.0"
+azure-monitor-query = "2.0.0"
azure-storage-blob = "12.24.1"
boto3 = "1.39.15"
botocore = "1.39.15"
@@ -4031,8 +4627,10 @@ detect-secrets = "1.5.0"
dulwich = "0.23.0"
google-api-python-client = "2.163.0"
google-auth-httplib2 = ">=0.1,<0.3"
+h2 = "4.3.0"
jsonschema = "4.23.0"
kubernetes = "32.0.1"
+markdown = "3.9.0"
microsoft-kiota-abstractions = "1.9.2"
msgraph-sdk = "1.23.0"
numpy = "2.0.2"
@@ -4053,7 +4651,7 @@ tzlocal = "5.3.1"
type = "git"
url = "https://github.com/prowler-cloud/prowler.git"
reference = "master"
-resolved_reference = "525f152e51f82de2110ed158c8dc489e42c289cf"
+resolved_reference = "a52697bfdfee83d14a49c11dcbe96888b5cd767e"
[[package]]
name = "psutil"
@@ -4922,6 +5520,29 @@ attrs = ">=22.2.0"
rpds-py = ">=0.7.0"
typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""}
+[[package]]
+name = "reportlab"
+version = "4.4.4"
+description = "The Reportlab Toolkit"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "reportlab-4.4.4-py3-none-any.whl", hash = "sha256:299b3b0534e7202bb94ed2ddcd7179b818dcda7de9d8518a57c85a58a1ebaadb"},
+ {file = "reportlab-4.4.4.tar.gz", hash = "sha256:cb2f658b7f4a15be2cc68f7203aa67faef67213edd4f2d4bdd3eb20dab75a80d"},
+]
+
+[package.dependencies]
+charset-normalizer = "*"
+pillow = ">=9.0.0"
+
+[package.extras]
+accel = ["rl_accel (>=0.9.0,<1.1)"]
+bidi = ["rlbidi"]
+pycairo = ["freetype-py (>=2.3.0,<2.4)", "rlPyCairo (>=0.2.0,<1)"]
+renderpm = ["rl_renderPM (>=4.0.3,<4.1)"]
+shaping = ["uharfbuzz"]
+
[[package]]
name = "requests"
version = "2.32.5"
@@ -5223,6 +5844,7 @@ files = [
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"},
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"},
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"},
+ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"},
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"},
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"},
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"},
@@ -5231,6 +5853,7 @@ files = [
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"},
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"},
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"},
+ {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"},
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"},
{file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"},
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"},
@@ -5239,6 +5862,7 @@ files = [
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"},
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"},
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"},
+ {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"},
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"},
{file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"},
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"},
@@ -5247,6 +5871,7 @@ files = [
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"},
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"},
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"},
+ {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"},
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"},
{file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"},
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"},
@@ -5255,6 +5880,7 @@ files = [
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"},
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"},
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"},
+ {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"},
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"},
{file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"},
{file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"},
@@ -6160,4 +6786,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.11,<3.13"
-content-hash = "b954196aba7e108cacb94fd15732be7130b27379add09140fabbb55f7335bb7b"
+content-hash = "943e2cd6b87229704550d4e140b36509fb9f58896ebb5834b9fbabe28a9ee92f"
diff --git a/api/pyproject.toml b/api/pyproject.toml
index 3a597281cc..ffc8413489 100644
--- a/api/pyproject.toml
+++ b/api/pyproject.toml
@@ -7,7 +7,7 @@ authors = [{name = "Prowler Engineering", email = "engineering@prowler.com"}]
dependencies = [
"celery[pytest] (>=5.4.0,<6.0.0)",
"dj-rest-auth[with_social,jwt] (==7.0.1)",
- "django==5.1.10",
+ "django (==5.1.14)",
"django-allauth[saml] (>=65.8.0,<66.0.0)",
"django-celery-beat (>=2.7.0,<3.0.0)",
"django-celery-results (>=2.5.1,<3.0.0)",
@@ -31,7 +31,11 @@ dependencies = [
"uuid6==2024.7.10",
"openai (>=1.82.0,<2.0.0)",
"xmlsec==1.3.14",
- "h2 (==4.3.0)"
+ "h2 (==4.3.0)",
+ "markdown (>=3.9,<4.0)",
+ "drf-simple-apikey (==2.2.1)",
+ "matplotlib (>=3.10.6,<4.0.0)",
+ "reportlab (>=4.4.4,<5.0.0)"
]
description = "Prowler's API (Django/DRF)"
license = "Apache-2.0"
@@ -39,7 +43,7 @@ name = "prowler-api"
package-mode = false
# Needed for the SDK compatibility
requires-python = ">=3.11,<3.13"
-version = "1.12.0"
+version = "1.15.0"
[project.scripts]
celery = "src.backend.config.settings.celery"
diff --git a/api/src/backend/api/admin.py b/api/src/backend/api/admin.py
deleted file mode 100644
index 4185d360e9..0000000000
--- a/api/src/backend/api/admin.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# from django.contrib import admin
-
-# Register your models here.
diff --git a/api/src/backend/api/apps.py b/api/src/backend/api/apps.py
index bfd78e30c7..add97cf376 100644
--- a/api/src/backend/api/apps.py
+++ b/api/src/backend/api/apps.py
@@ -1,4 +1,26 @@
+import logging
+import os
+import sys
+from pathlib import Path
+
+from config.custom_logging import BackendLogger
+from config.env import env
from django.apps import AppConfig
+from django.conf import settings
+
+logger = logging.getLogger(BackendLogger.API)
+
+SIGNING_KEY_ENV = "DJANGO_TOKEN_SIGNING_KEY"
+VERIFYING_KEY_ENV = "DJANGO_TOKEN_VERIFYING_KEY"
+
+PRIVATE_KEY_FILE = "jwt_private.pem"
+PUBLIC_KEY_FILE = "jwt_public.pem"
+
+KEYS_DIRECTORY = (
+ Path.home() / ".config" / "prowler-api"
+) # `/home/prowler/.config/prowler-api` inside the container
+
+_keys_initialized = False # Flag to prevent multiple executions within the same process
class ApiConfig(AppConfig):
@@ -6,7 +28,142 @@ class ApiConfig(AppConfig):
name = "api"
def ready(self):
+ from api import schema_extensions # noqa: F401
from api import signals # noqa: F401
from api.compliance import load_prowler_compliance
+ # Generate required cryptographic keys if not present, but only if:
+ # `"manage.py" not in sys.argv`: If an external server (e.g., Gunicorn) is running the app
+ # `os.environ.get("RUN_MAIN")`: If it's not a Django command or using `runserver`,
+ # only the main process will do it
+ if "manage.py" not in sys.argv or os.environ.get("RUN_MAIN"):
+ self._ensure_crypto_keys()
+
load_prowler_compliance()
+
+ def _ensure_crypto_keys(self):
+ """
+ Orchestrator method that ensures all required cryptographic keys are present.
+ This method coordinates the generation of:
+ - RSA key pairs for JWT token signing and verification
+ Note: During development, Django spawns multiple processes (migrations, fixtures, etc.)
+ which will each generate their own keys. This is expected behavior and each process
+ will have consistent keys for its lifetime. In production, set the keys as environment
+ variables to avoid regeneration.
+ """
+ global _keys_initialized
+
+ # Skip key generation if running tests
+ if hasattr(settings, "TESTING") and settings.TESTING:
+ return
+
+ # Skip if already initialized in this process
+ if _keys_initialized:
+ return
+
+ # Check if both JWT keys are set; if not, generate them
+ signing_key = env.str(SIGNING_KEY_ENV, default="").strip()
+ verifying_key = env.str(VERIFYING_KEY_ENV, default="").strip()
+
+ if not signing_key or not verifying_key:
+ logger.info(
+ f"Generating JWT RSA key pair. In production, set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' "
+ "environment variables."
+ )
+ self._ensure_jwt_keys()
+
+ # Mark as initialized to prevent future executions in this process
+ _keys_initialized = True
+
+ def _read_key_file(self, file_name):
+ """
+ Utility method to read the contents of a file.
+ """
+ file_path = KEYS_DIRECTORY / file_name
+ return file_path.read_text().strip() if file_path.is_file() else None
+
+ def _write_key_file(self, file_name, content, private=True):
+ """
+ Utility method to write content to a file.
+ """
+ try:
+ file_path = KEYS_DIRECTORY / file_name
+ file_path.parent.mkdir(parents=True, exist_ok=True)
+ file_path.write_text(content)
+ file_path.chmod(0o600 if private else 0o644)
+
+ except Exception as e:
+ logger.error(
+ f"Error writing key file '{file_name}': {e}. "
+ f"Please set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' manually."
+ )
+ raise e
+
+ def _ensure_jwt_keys(self):
+ """
+ Generate RSA key pairs for JWT token signing and verification
+ if they are not already set in environment variables.
+ """
+ # Read existing keys from files if they exist
+ signing_key = self._read_key_file(PRIVATE_KEY_FILE)
+ verifying_key = self._read_key_file(PUBLIC_KEY_FILE)
+
+ if not signing_key or not verifying_key:
+ # Generate and store the RSA key pair
+ signing_key, verifying_key = self._generate_jwt_keys()
+ self._write_key_file(PRIVATE_KEY_FILE, signing_key, private=True)
+ self._write_key_file(PUBLIC_KEY_FILE, verifying_key, private=False)
+ logger.info("JWT keys generated and stored successfully")
+
+ else:
+ logger.info("JWT keys already generated")
+
+ # Set environment variables and Django settings
+ os.environ[SIGNING_KEY_ENV] = signing_key
+ settings.SIMPLE_JWT["SIGNING_KEY"] = signing_key
+
+ os.environ[VERIFYING_KEY_ENV] = verifying_key
+ settings.SIMPLE_JWT["VERIFYING_KEY"] = verifying_key
+
+ def _generate_jwt_keys(self):
+ """
+ Generate and set RSA key pairs for JWT token operations.
+ """
+ try:
+ from cryptography.hazmat.primitives import serialization
+ from cryptography.hazmat.primitives.asymmetric import rsa
+
+ # Generate RSA key pair
+ private_key = rsa.generate_private_key( # Future improvement: we could read the next values from env vars
+ public_exponent=65537,
+ key_size=2048,
+ )
+
+ # Serialize private key (for signing)
+ private_pem = private_key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.PKCS8,
+ encryption_algorithm=serialization.NoEncryption(),
+ ).decode("utf-8")
+
+ # Serialize public key (for verification)
+ public_key = private_key.public_key()
+ public_pem = public_key.public_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
+ ).decode("utf-8")
+
+ logger.debug("JWT RSA key pair generated successfully.")
+ return private_pem, public_pem
+
+ except ImportError as e:
+ logger.warning(
+ "The 'cryptography' package is required for automatic JWT key generation."
+ )
+ raise e
+
+ except Exception as e:
+ logger.error(
+ f"Error generating JWT keys: {e}. Please set '{SIGNING_KEY_ENV}' and '{VERIFYING_KEY_ENV}' manually."
+ )
+ raise e
diff --git a/api/src/backend/api/authentication.py b/api/src/backend/api/authentication.py
new file mode 100644
index 0000000000..499e290bb7
--- /dev/null
+++ b/api/src/backend/api/authentication.py
@@ -0,0 +1,95 @@
+from typing import Optional, Tuple
+from uuid import UUID
+
+from cryptography.fernet import InvalidToken
+from django.utils import timezone
+from drf_simple_apikey.backends import APIKeyAuthentication as BaseAPIKeyAuth
+from drf_simple_apikey.crypto import get_crypto
+from rest_framework.authentication import BaseAuthentication
+from rest_framework.exceptions import AuthenticationFailed
+from rest_framework.request import Request
+from rest_framework_simplejwt.authentication import JWTAuthentication
+
+from api.db_router import MainRouter
+from api.models import TenantAPIKey, TenantAPIKeyManager
+
+
+class TenantAPIKeyAuthentication(BaseAPIKeyAuth):
+ model = TenantAPIKey
+
+ def __init__(self):
+ self.key_crypto = get_crypto()
+
+ def _authenticate_credentials(self, request, key):
+ """
+ Override to use admin connection, bypassing RLS during authentication.
+ Delegates to parent after temporarily routing model queries to admin DB.
+ """
+ # Temporarily point the model's manager to admin database
+ original_objects = self.model.objects
+ self.model.objects = self.model.objects.using(MainRouter.admin_db)
+
+ try:
+ # Call parent method which will now use admin database
+ return super()._authenticate_credentials(request, key)
+ finally:
+ # Restore original manager
+ self.model.objects = original_objects
+
+ def authenticate(self, request: Request):
+ prefixed_key = self.get_key(request)
+
+ # Split prefix from key (format: pk_xxxxxxxx.encrypted_key)
+ try:
+ prefix, key = prefixed_key.split(TenantAPIKeyManager.separator, 1)
+ except ValueError:
+ raise AuthenticationFailed("Invalid API Key.")
+
+ try:
+ entity, _ = self._authenticate_credentials(request, key)
+ except InvalidToken:
+ raise AuthenticationFailed("Invalid API Key.")
+
+ # Get the API key instance to update last_used_at and retrieve tenant info
+ # We need to decrypt again to get the pk (already validated by _authenticate_credentials)
+ payload = self.key_crypto.decrypt(key)
+ api_key_pk = payload["_pk"]
+
+ # Convert string UUID back to UUID object for lookup
+ if isinstance(api_key_pk, str):
+ api_key_pk = UUID(api_key_pk)
+
+ try:
+ api_key_instance = TenantAPIKey.objects.using(MainRouter.admin_db).get(
+ id=api_key_pk, prefix=prefix
+ )
+ except TenantAPIKey.DoesNotExist:
+ raise AuthenticationFailed("Invalid API Key.")
+
+ # Update last_used_at
+ api_key_instance.last_used_at = timezone.now()
+ api_key_instance.save(update_fields=["last_used_at"], using=MainRouter.admin_db)
+
+ return entity, {
+ "tenant_id": str(api_key_instance.tenant_id),
+ "sub": str(api_key_instance.entity.id),
+ "api_key_prefix": prefix,
+ }
+
+
+class CombinedJWTOrAPIKeyAuthentication(BaseAuthentication):
+ jwt_auth = JWTAuthentication()
+ api_key_auth = TenantAPIKeyAuthentication()
+
+ def authenticate(self, request: Request) -> Optional[Tuple[object, dict]]:
+ auth_header = request.headers.get("Authorization", "")
+
+ # Prioritize JWT authentication if both are present
+ if auth_header.startswith("Bearer "):
+ return self.jwt_auth.authenticate(request)
+
+ if auth_header.startswith("Api-Key "):
+ return self.api_key_auth.authenticate(request)
+
+ # Default fallback
+ return self.jwt_auth.authenticate(request)
diff --git a/api/src/backend/api/base_views.py b/api/src/backend/api/base_views.py
index 605afe332d..7cdf8fdd7f 100644
--- a/api/src/backend/api/base_views.py
+++ b/api/src/backend/api/base_views.py
@@ -1,13 +1,15 @@
+from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from rest_framework import permissions
from rest_framework.exceptions import NotAuthenticated
from rest_framework.filters import SearchFilter
+from rest_framework.permissions import SAFE_METHODS
from rest_framework_json_api import filters
from rest_framework_json_api.views import ModelViewSet
-from rest_framework_simplejwt.authentication import JWTAuthentication
-from api.db_router import MainRouter
+from api.authentication import CombinedJWTOrAPIKeyAuthentication
+from api.db_router import MainRouter, reset_read_db_alias, set_read_db_alias
from api.db_utils import POSTGRES_USER_VAR, rls_transaction
from api.filters import CustomDjangoFilterBackend
from api.models import Role, Tenant
@@ -15,7 +17,7 @@ from api.rbac.permissions import HasPermissions
class BaseViewSet(ModelViewSet):
- authentication_classes = [JWTAuthentication]
+ authentication_classes = [CombinedJWTOrAPIKeyAuthentication]
required_permissions = []
permission_classes = [permissions.IsAuthenticated, HasPermissions]
filter_backends = [
@@ -31,6 +33,20 @@ class BaseViewSet(ModelViewSet):
ordering_fields = "__all__"
ordering = ["id"]
+ def _get_request_db_alias(self, request):
+ if request is None:
+ return MainRouter.default_db
+
+ read_alias = (
+ MainRouter.replica_db
+ if request.method in SAFE_METHODS
+ and MainRouter.replica_db in settings.DATABASES
+ else None
+ )
+ if read_alias:
+ return read_alias
+ return MainRouter.default_db
+
def initial(self, request, *args, **kwargs):
"""
Sets required_permissions before permissions are checked.
@@ -48,8 +64,21 @@ class BaseViewSet(ModelViewSet):
class BaseRLSViewSet(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
- with transaction.atomic():
- return super().dispatch(request, *args, **kwargs)
+ self.db_alias = self._get_request_db_alias(request)
+ alias_token = None
+ try:
+ if self.db_alias != MainRouter.default_db:
+ alias_token = set_read_db_alias(self.db_alias)
+
+ if request is not None:
+ request.db_alias = self.db_alias
+
+ with transaction.atomic(using=self.db_alias):
+ return super().dispatch(request, *args, **kwargs)
+ finally:
+ if alias_token is not None:
+ reset_read_db_alias(alias_token)
+ self.db_alias = MainRouter.default_db
def initial(self, request, *args, **kwargs):
# Ideally, this logic would be in the `.setup()` method but DRF view sets don't call it
@@ -61,7 +90,9 @@ class BaseRLSViewSet(BaseViewSet):
if tenant_id is None:
raise NotAuthenticated("Tenant ID is not present in token")
- with rls_transaction(tenant_id):
+ with rls_transaction(
+ tenant_id, using=getattr(self, "db_alias", MainRouter.default_db)
+ ):
self.request.tenant_id = tenant_id
return super().initial(request, *args, **kwargs)
@@ -73,18 +104,33 @@ class BaseRLSViewSet(BaseViewSet):
class BaseTenantViewset(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
- with transaction.atomic():
- tenant = super().dispatch(request, *args, **kwargs)
-
+ self.db_alias = self._get_request_db_alias(request)
+ alias_token = None
try:
- # If the request is a POST, create the admin role
- if request.method == "POST":
- isinstance(tenant, dict) and self._create_admin_role(tenant.data["id"])
- except Exception as e:
- self._handle_creation_error(e, tenant)
- raise
+ if self.db_alias != MainRouter.default_db:
+ alias_token = set_read_db_alias(self.db_alias)
- return tenant
+ if request is not None:
+ request.db_alias = self.db_alias
+
+ with transaction.atomic(using=self.db_alias):
+ tenant = super().dispatch(request, *args, **kwargs)
+
+ try:
+ # If the request is a POST, create the admin role
+ if request.method == "POST":
+ isinstance(tenant, dict) and self._create_admin_role(
+ tenant.data["id"]
+ )
+ except Exception as e:
+ self._handle_creation_error(e, tenant)
+ raise
+
+ return tenant
+ finally:
+ if alias_token is not None:
+ reset_read_db_alias(alias_token)
+ self.db_alias = MainRouter.default_db
def _create_admin_role(self, tenant_id):
Role.objects.using(MainRouter.admin_db).create(
@@ -117,14 +163,31 @@ class BaseTenantViewset(BaseViewSet):
raise NotAuthenticated("Tenant ID is not present in token")
user_id = str(request.user.id)
- with rls_transaction(value=user_id, parameter=POSTGRES_USER_VAR):
+ with rls_transaction(
+ value=user_id,
+ parameter=POSTGRES_USER_VAR,
+ using=getattr(self, "db_alias", MainRouter.default_db),
+ ):
return super().initial(request, *args, **kwargs)
class BaseUserViewset(BaseViewSet):
def dispatch(self, request, *args, **kwargs):
- with transaction.atomic():
- return super().dispatch(request, *args, **kwargs)
+ self.db_alias = self._get_request_db_alias(request)
+ alias_token = None
+ try:
+ if self.db_alias != MainRouter.default_db:
+ alias_token = set_read_db_alias(self.db_alias)
+
+ if request is not None:
+ request.db_alias = self.db_alias
+
+ with transaction.atomic(using=self.db_alias):
+ return super().dispatch(request, *args, **kwargs)
+ finally:
+ if alias_token is not None:
+ reset_read_db_alias(alias_token)
+ self.db_alias = MainRouter.default_db
def initial(self, request, *args, **kwargs):
# TODO refactor after improving RLS on users
@@ -137,6 +200,8 @@ class BaseUserViewset(BaseViewSet):
if tenant_id is None:
raise NotAuthenticated("Tenant ID is not present in token")
- with rls_transaction(tenant_id):
+ with rls_transaction(
+ tenant_id, using=getattr(self, "db_alias", MainRouter.default_db)
+ ):
self.request.tenant_id = tenant_id
return super().initial(request, *args, **kwargs)
diff --git a/api/src/backend/api/compliance.py b/api/src/backend/api/compliance.py
index 1773a9a820..da39fc23bb 100644
--- a/api/src/backend/api/compliance.py
+++ b/api/src/backend/api/compliance.py
@@ -144,18 +144,23 @@ def generate_scan_compliance(
Returns:
None: This function modifies the compliance_overview in place.
"""
+
for compliance_id in PROWLER_CHECKS[provider_type][check_id]:
for requirement in compliance_overview[compliance_id]["requirements"].values():
if check_id in requirement["checks"]:
requirement["checks"][check_id] = status
requirement["checks_status"][status.lower()] += 1
- if requirement["status"] != "FAIL" and any(
- value == "FAIL" for value in requirement["checks"].values()
- ):
- requirement["status"] = "FAIL"
- compliance_overview[compliance_id]["requirements_status"]["passed"] -= 1
- compliance_overview[compliance_id]["requirements_status"]["failed"] += 1
+ if requirement["status"] != "FAIL" and any(
+ value == "FAIL" for value in requirement["checks"].values()
+ ):
+ requirement["status"] = "FAIL"
+ compliance_overview[compliance_id]["requirements_status"][
+ "passed"
+ ] -= 1
+ compliance_overview[compliance_id]["requirements_status"][
+ "failed"
+ ] += 1
def generate_compliance_overview_template(prowler_compliance: dict):
@@ -225,6 +230,7 @@ def generate_compliance_overview_template(prowler_compliance: dict):
# Build compliance dictionary
compliance_dict = {
"framework": compliance_data.Framework,
+ "name": compliance_data.Name,
"version": compliance_data.Version,
"provider": provider_type,
"description": compliance_data.Description,
diff --git a/api/src/backend/api/db_router.py b/api/src/backend/api/db_router.py
index dc34c1191a..2a9085746e 100644
--- a/api/src/backend/api/db_router.py
+++ b/api/src/backend/api/db_router.py
@@ -1,9 +1,31 @@
+from contextvars import ContextVar
+
+from django.conf import settings
+
ALLOWED_APPS = ("django", "socialaccount", "account", "authtoken", "silk")
+_read_db_alias = ContextVar("read_db_alias", default=None)
+
+
+def set_read_db_alias(alias: str | None):
+ if not alias:
+ return None
+ return _read_db_alias.set(alias)
+
+
+def get_read_db_alias() -> str | None:
+ return _read_db_alias.get()
+
+
+def reset_read_db_alias(token) -> None:
+ if token is not None:
+ _read_db_alias.reset(token)
+
class MainRouter:
default_db = "default"
admin_db = "admin"
+ replica_db = "replica"
def db_for_read(self, model, **hints): # noqa: F841
model_table_name = model._meta.db_table
@@ -11,6 +33,9 @@ class MainRouter:
model_table_name.startswith(f"{app}_") for app in ALLOWED_APPS
):
return self.admin_db
+ read_alias = get_read_db_alias()
+ if read_alias:
+ return read_alias
return None
def db_for_write(self, model, **hints): # noqa: F841
@@ -23,7 +48,13 @@ class MainRouter:
return db == self.admin_db
def allow_relation(self, obj1, obj2, **hints): # noqa: F841
- # Allow relations if both objects are in either "default" or "admin" db connectors
- if {obj1._state.db, obj2._state.db} <= {self.default_db, self.admin_db}:
+ # Allow relations when both objects originate from allowed connectors
+ allowed_dbs = {self.default_db, self.admin_db, self.replica_db}
+ if {obj1._state.db, obj2._state.db} <= allowed_dbs:
return True
return None
+
+
+READ_REPLICA_ALIAS = (
+ MainRouter.replica_db if MainRouter.replica_db in settings.DATABASES else None
+)
diff --git a/api/src/backend/api/db_utils.py b/api/src/backend/api/db_utils.py
index d7ec718f11..c6fcaeb43a 100644
--- a/api/src/backend/api/db_utils.py
+++ b/api/src/backend/api/db_utils.py
@@ -1,17 +1,36 @@
import re
import secrets
+import time
import uuid
from contextlib import contextmanager
from datetime import datetime, timedelta, timezone
+from celery.utils.log import get_task_logger
+from config.env import env
from django.conf import settings
from django.contrib.auth.models import BaseUserManager
-from django.db import connection, models, transaction
+from django.db import (
+ DEFAULT_DB_ALIAS,
+ OperationalError,
+ connection,
+ connections,
+ models,
+ transaction,
+)
from django_celery_beat.models import PeriodicTask
from psycopg2 import connect as psycopg2_connect
from psycopg2.extensions import AsIs, new_type, register_adapter, register_type
from rest_framework_json_api.serializers import ValidationError
+from api.db_router import (
+ READ_REPLICA_ALIAS,
+ get_read_db_alias,
+ reset_read_db_alias,
+ set_read_db_alias,
+)
+
+logger = get_task_logger(__name__)
+
DB_USER = settings.DATABASES["default"]["USER"] if not settings.TESTING else "test"
DB_PASSWORD = (
settings.DATABASES["default"]["PASSWORD"] if not settings.TESTING else "test"
@@ -26,6 +45,9 @@ TASK_RUNNER_DB_TABLE = "django_celery_results_taskresult"
POSTGRES_TENANT_VAR = "api.tenant_id"
POSTGRES_USER_VAR = "api.user_id"
+REPLICA_MAX_ATTEMPTS = env.int("POSTGRES_REPLICA_MAX_ATTEMPTS", default=3)
+REPLICA_RETRY_BASE_DELAY = env.float("POSTGRES_REPLICA_RETRY_BASE_DELAY", default=0.5)
+
SET_CONFIG_QUERY = "SELECT set_config(%s, %s::text, TRUE);"
@@ -49,7 +71,11 @@ def psycopg_connection(database_alias: str):
@contextmanager
-def rls_transaction(value: str, parameter: str = POSTGRES_TENANT_VAR):
+def rls_transaction(
+ value: str,
+ parameter: str = POSTGRES_TENANT_VAR,
+ using: str | None = None,
+):
"""
Creates a new database transaction setting the given configuration value for Postgres RLS. It validates the
if the value is a valid UUID.
@@ -57,16 +83,59 @@ def rls_transaction(value: str, parameter: str = POSTGRES_TENANT_VAR):
Args:
value (str): Database configuration parameter value.
parameter (str): Database configuration parameter name, by default is 'api.tenant_id'.
+ using (str | None): Optional database alias to run the transaction against. Defaults to the
+ active read alias (if any) or Django's default connection.
"""
- with transaction.atomic():
- with connection.cursor() as cursor:
- try:
- # just in case the value is an UUID object
- uuid.UUID(str(value))
- except ValueError:
- raise ValidationError("Must be a valid UUID")
- cursor.execute(SET_CONFIG_QUERY, [parameter, value])
- yield cursor
+ requested_alias = using or get_read_db_alias()
+ db_alias = requested_alias or DEFAULT_DB_ALIAS
+ if db_alias not in connections:
+ db_alias = DEFAULT_DB_ALIAS
+
+ alias = db_alias
+ is_replica = READ_REPLICA_ALIAS and alias == READ_REPLICA_ALIAS
+ max_attempts = REPLICA_MAX_ATTEMPTS if is_replica else 1
+
+ for attempt in range(1, max_attempts + 1):
+ router_token = None
+
+ # On final attempt, fallback to primary
+ if attempt == max_attempts and is_replica:
+ logger.warning(
+ f"RLS transaction failed after {attempt - 1} attempts on replica, "
+ f"falling back to primary DB"
+ )
+ alias = DEFAULT_DB_ALIAS
+
+ conn = connections[alias]
+ try:
+ if alias != DEFAULT_DB_ALIAS:
+ router_token = set_read_db_alias(alias)
+
+ with transaction.atomic(using=alias):
+ with conn.cursor() as cursor:
+ try:
+ # just in case the value is a UUID object
+ uuid.UUID(str(value))
+ except ValueError:
+ raise ValidationError("Must be a valid UUID")
+ cursor.execute(SET_CONFIG_QUERY, [parameter, value])
+ yield cursor
+ return
+ except OperationalError as e:
+ # If on primary or max attempts reached, raise
+ if not is_replica or attempt == max_attempts:
+ raise
+
+ # Retry with exponential backoff
+ delay = REPLICA_RETRY_BASE_DELAY * (2 ** (attempt - 1))
+ logger.info(
+ f"RLS transaction failed on replica (attempt {attempt}/{max_attempts}), "
+ f"retrying in {delay}s. Error: {e}"
+ )
+ time.sleep(delay)
+ finally:
+ if router_token is not None:
+ reset_read_db_alias(router_token)
class CustomUserManager(BaseUserManager):
@@ -434,6 +503,12 @@ def drop_index_on_partitions(
schema_editor.execute(sql)
+def generate_api_key_prefix():
+ """Generate a random 8-character prefix for API keys (e.g., 'pk_abc123de')."""
+ random_chars = generate_random_token(length=8)
+ return f"pk_{random_chars}"
+
+
# Postgres enum definition for member role
diff --git a/api/src/backend/api/exceptions.py b/api/src/backend/api/exceptions.py
index b622118674..d1cf7d78ce 100644
--- a/api/src/backend/api/exceptions.py
+++ b/api/src/backend/api/exceptions.py
@@ -1,6 +1,10 @@
from django.core.exceptions import ValidationError as django_validation_error
from rest_framework import status
-from rest_framework.exceptions import APIException
+from rest_framework.exceptions import (
+ APIException,
+ AuthenticationFailed,
+ NotAuthenticated,
+)
from rest_framework_json_api.exceptions import exception_handler
from rest_framework_json_api.serializers import ValidationError
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
@@ -68,15 +72,18 @@ def custom_exception_handler(exc, context):
exc = ValidationError(exc.message_dict)
else:
exc = ValidationError(detail=exc.messages[0], code=exc.code)
- elif isinstance(exc, (TokenError, InvalidToken)):
- if (
- hasattr(exc, "detail")
- and isinstance(exc.detail, dict)
- and "messages" in exc.detail
- ):
- exc.detail["messages"] = [
- message_item["message"] for message_item in exc.detail["messages"]
- ]
+ # Force 401 status for AuthenticationFailed exceptions regardless of the authentication backend
+ elif isinstance(exc, (AuthenticationFailed, NotAuthenticated, TokenError)):
+ exc.status_code = status.HTTP_401_UNAUTHORIZED
+ if isinstance(exc, (TokenError, InvalidToken)):
+ if (
+ hasattr(exc, "detail")
+ and isinstance(exc.detail, dict)
+ and "messages" in exc.detail
+ ):
+ exc.detail["messages"] = [
+ message_item["message"] for message_item in exc.detail["messages"]
+ ]
return exception_handler(exc, context)
diff --git a/api/src/backend/api/filters.py b/api/src/backend/api/filters.py
index 7418d2daf9..de1397b117 100644
--- a/api/src/backend/api/filters.py
+++ b/api/src/backend/api/filters.py
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta, timezone
from dateutil.parser import parse
from django.conf import settings
-from django.db.models import Q
+from django.db.models import F, Q
from django_filters.rest_framework import (
BaseInFilter,
BooleanFilter,
@@ -27,7 +27,11 @@ from api.models import (
Finding,
Integration,
Invitation,
+ LighthouseProviderConfiguration,
+ LighthouseProviderModels,
Membership,
+ MuteRule,
+ OverviewStatusChoices,
PermissionChoices,
Processor,
Provider,
@@ -42,6 +46,8 @@ from api.models import (
StateChoices,
StatusChoices,
Task,
+ TenantAPIKey,
+ ThreatScoreSnapshot,
User,
)
from api.rls import Tenant
@@ -218,10 +224,39 @@ class MembershipFilter(FilterSet):
class ProviderFilter(FilterSet):
- inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
- updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
- connected = BooleanFilter()
+ inserted_at = DateFilter(
+ field_name="inserted_at",
+ lookup_expr="date",
+ help_text="""Filter by date when the provider was added
+ (format: YYYY-MM-DD)""",
+ )
+ updated_at = DateFilter(
+ field_name="updated_at",
+ lookup_expr="date",
+ help_text="""Filter by date when the provider was updated
+ (format: YYYY-MM-DD)""",
+ )
+ connected = BooleanFilter(
+ help_text="""Filter by connection status. Set to True to return only
+ connected providers, or False to return only providers with failed
+ connections. If not specified, both connected and failed providers are
+ included. Providers with no connection attempt (status is null) are
+ excluded from this filter."""
+ )
provider = ChoiceFilter(choices=Provider.ProviderChoices.choices)
+ provider__in = ChoiceInFilter(
+ field_name="provider",
+ choices=Provider.ProviderChoices.choices,
+ lookup_expr="in",
+ )
+ provider_type = ChoiceFilter(
+ choices=Provider.ProviderChoices.choices, field_name="provider"
+ )
+ provider_type__in = ChoiceInFilter(
+ field_name="provider",
+ choices=Provider.ProviderChoices.choices,
+ lookup_expr="in",
+ )
class Meta:
model = Provider
@@ -647,8 +682,16 @@ class LatestFindingFilter(CommonFindingFilters):
class ProviderSecretFilter(FilterSet):
- inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
- updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
+ inserted_at = DateFilter(
+ field_name="inserted_at",
+ lookup_expr="date",
+ help_text="Filter by date when the secret was added (format: YYYY-MM-DD)",
+ )
+ updated_at = DateFilter(
+ field_name="updated_at",
+ lookup_expr="date",
+ help_text="Filter by date when the secret was updated (format: YYYY-MM-DD)",
+ )
provider = UUIDFilter(field_name="provider__id", lookup_expr="exact")
class Meta:
@@ -718,6 +761,14 @@ class RoleFilter(FilterSet):
class ComplianceOverviewFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
scan_id = UUIDFilter(field_name="scan_id")
+ provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
+ provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
+ provider_type = ChoiceFilter(
+ field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
+ )
+ provider_type__in = ChoiceInFilter(
+ field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
+ )
region = CharFilter(field_name="region")
class Meta:
@@ -734,6 +785,7 @@ class ComplianceOverviewFilter(FilterSet):
class ScanSummaryFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
+ provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
)
@@ -750,24 +802,70 @@ class ScanSummaryFilter(FilterSet):
}
-class ServiceOverviewFilter(ScanSummaryFilter):
- def is_valid(self):
- # Check if at least one of the inserted_at filters is present
- inserted_at_filters = [
- self.data.get("inserted_at"),
- self.data.get("inserted_at__gte"),
- self.data.get("inserted_at__lte"),
- ]
- if not any(inserted_at_filters):
- raise ValidationError(
- {
- "inserted_at": [
- "At least one of filter[inserted_at], filter[inserted_at__gte], or "
- "filter[inserted_at__lte] is required."
- ]
- }
- )
- return super().is_valid()
+class ScanSummarySeverityFilter(ScanSummaryFilter):
+ """Filter for findings_severity ScanSummary endpoint - includes status filters"""
+
+ # Custom status filters - only for severity grouping endpoint
+ status = ChoiceFilter(method="filter_status", choices=OverviewStatusChoices.choices)
+ status__in = CharInFilter(method="filter_status_in", lookup_expr="in")
+
+ def filter_status(self, queryset, name, value):
+ # Validate the status value
+ if value not in [choice[0] for choice in OverviewStatusChoices.choices]:
+ raise ValidationError(f"Invalid status value: {value}")
+
+ # Apply the filter by annotating the queryset with the status field
+ if value == OverviewStatusChoices.FAIL:
+ return queryset.annotate(status_count=F("fail"))
+ elif value == OverviewStatusChoices.PASS:
+ return queryset.annotate(status_count=F("_pass"))
+ else:
+ return queryset.annotate(status_count=F("total"))
+
+ def filter_status_in(self, queryset, name, value):
+ # Validate the status values
+ valid_statuses = [choice[0] for choice in OverviewStatusChoices.choices]
+ for status_val in value:
+ if status_val not in valid_statuses:
+ raise ValidationError(f"Invalid status value: {status_val}")
+
+ # If all statuses or no valid statuses, use total
+ if (
+ set(value)
+ >= {
+ OverviewStatusChoices.FAIL,
+ OverviewStatusChoices.PASS,
+ }
+ or not value
+ ):
+ return queryset.annotate(status_count=F("total"))
+
+ # Build the sum expression based on status values
+ sum_expression = None
+ for status in value:
+ if status == OverviewStatusChoices.FAIL:
+ field_expr = F("fail")
+ elif status == OverviewStatusChoices.PASS:
+ field_expr = F("_pass")
+ else:
+ continue
+
+ if sum_expression is None:
+ sum_expression = field_expr
+ else:
+ sum_expression = sum_expression + field_expr
+
+ if sum_expression is None:
+ return queryset.annotate(status_count=F("total"))
+
+ return queryset.annotate(status_count=sum_expression)
+
+ class Meta:
+ model = ScanSummary
+ fields = {
+ "inserted_at": ["date", "gte", "lte"],
+ "region": ["exact", "icontains", "in"],
+ }
class IntegrationFilter(FilterSet):
@@ -793,3 +891,132 @@ class ProcessorFilter(FilterSet):
field_name="processor_type",
lookup_expr="in",
)
+
+
+class IntegrationJiraFindingsFilter(FilterSet):
+ # To be expanded as needed
+ finding_id = UUIDFilter(field_name="id", lookup_expr="exact")
+ finding_id__in = UUIDInFilter(field_name="id", lookup_expr="in")
+
+ class Meta:
+ model = Finding
+ fields = {}
+
+ def filter_queryset(self, queryset):
+ # Validate that there is at least one filter provided
+ if not self.data:
+ raise ValidationError(
+ {
+ "findings": "No finding filters provided. At least one filter is required."
+ }
+ )
+ return super().filter_queryset(queryset)
+
+
+class TenantApiKeyFilter(FilterSet):
+ inserted_at = DateFilter(field_name="created", lookup_expr="date")
+ inserted_at__gte = DateFilter(field_name="created", lookup_expr="gte")
+ inserted_at__lte = DateFilter(field_name="created", lookup_expr="lte")
+ expires_at = DateFilter(field_name="expiry_date", lookup_expr="date")
+ expires_at__gte = DateFilter(field_name="expiry_date", lookup_expr="gte")
+ expires_at__lte = DateFilter(field_name="expiry_date", lookup_expr="lte")
+
+ class Meta:
+ model = TenantAPIKey
+ fields = {
+ "prefix": ["exact", "icontains"],
+ "revoked": ["exact"],
+ "name": ["exact", "icontains"],
+ }
+
+
+class LighthouseProviderConfigFilter(FilterSet):
+ provider_type = ChoiceFilter(
+ choices=LighthouseProviderConfiguration.LLMProviderChoices.choices
+ )
+ provider_type__in = ChoiceInFilter(
+ choices=LighthouseProviderConfiguration.LLMProviderChoices.choices,
+ field_name="provider_type",
+ lookup_expr="in",
+ )
+ is_active = BooleanFilter()
+
+ class Meta:
+ model = LighthouseProviderConfiguration
+ fields = {
+ "provider_type": ["exact", "in"],
+ "is_active": ["exact"],
+ }
+
+
+class LighthouseProviderModelsFilter(FilterSet):
+ provider_type = ChoiceFilter(
+ choices=LighthouseProviderConfiguration.LLMProviderChoices.choices,
+ field_name="provider_configuration__provider_type",
+ )
+ provider_type__in = ChoiceInFilter(
+ choices=LighthouseProviderConfiguration.LLMProviderChoices.choices,
+ field_name="provider_configuration__provider_type",
+ lookup_expr="in",
+ )
+
+ # Allow filtering by model id
+ model_id = CharFilter(field_name="model_id", lookup_expr="exact")
+ model_id__icontains = CharFilter(field_name="model_id", lookup_expr="icontains")
+ model_id__in = CharInFilter(field_name="model_id", lookup_expr="in")
+
+ class Meta:
+ model = LighthouseProviderModels
+ fields = {
+ "model_id": ["exact", "icontains", "in"],
+ }
+
+
+class MuteRuleFilter(FilterSet):
+ inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
+ updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
+ created_by = UUIDFilter(field_name="created_by__id", lookup_expr="exact")
+
+ class Meta:
+ model = MuteRule
+ fields = {
+ "id": ["exact", "in"],
+ "name": ["exact", "icontains"],
+ "reason": ["icontains"],
+ "enabled": ["exact"],
+ "inserted_at": ["gte", "lte"],
+ "updated_at": ["gte", "lte"],
+ }
+
+
+class ThreatScoreSnapshotFilter(FilterSet):
+ """
+ Filter for ThreatScore snapshots.
+ Allows filtering by scan, provider, compliance_id, and date ranges.
+ """
+
+ inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
+ scan_id = UUIDFilter(field_name="scan__id", lookup_expr="exact")
+ scan_id__in = UUIDInFilter(field_name="scan__id", lookup_expr="in")
+ provider_id = UUIDFilter(field_name="provider__id", lookup_expr="exact")
+ provider_id__in = UUIDInFilter(field_name="provider__id", lookup_expr="in")
+ provider_type = ChoiceFilter(
+ field_name="provider__provider", choices=Provider.ProviderChoices.choices
+ )
+ provider_type__in = ChoiceInFilter(
+ field_name="provider__provider",
+ choices=Provider.ProviderChoices.choices,
+ lookup_expr="in",
+ )
+ compliance_id = CharFilter(field_name="compliance_id", lookup_expr="exact")
+ compliance_id__in = CharInFilter(field_name="compliance_id", lookup_expr="in")
+
+ class Meta:
+ model = ThreatScoreSnapshot
+ fields = {
+ "scan": ["exact", "in"],
+ "provider": ["exact", "in"],
+ "compliance_id": ["exact", "in"],
+ "inserted_at": ["date", "gte", "lte"],
+ "overall_score": ["exact", "gte", "lte"],
+ }
diff --git a/api/src/backend/api/fixtures/dev/7_dev_compliance.json b/api/src/backend/api/fixtures/dev/7_dev_compliance.json
index 90a4bcd6be..b90ead642b 100644
--- a/api/src/backend/api/fixtures/dev/7_dev_compliance.json
+++ b/api/src/backend/api/fixtures/dev/7_dev_compliance.json
@@ -1 +1 @@
-[{"model": "api.complianceoverview","pk": "07d0c342-abcb-4d91-b865-88f9c96adbfc","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "cisa_aws","framework": "CISA","version": "","description": "Cybersecurity & Infrastructure Security Agency's (CISA) Cyber Essentials is a guide for leaders of small businesses as well as leaders of small and local government agencies to develop an actionable understanding of where to start implementing organizational cybersecurity practices.","region": "eu-west-1","requirements": {"your-data-1": {"name": "Your Data-1","checks": {"ec2_ebs_volume_encryption": "PASS","ec2_ebs_default_encryption": "PASS","s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_kms_encryption_enabled": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","dynamodb_tables_kms_cmk_encryption_enabled": null,"sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null,"sagemaker_training_jobs_volume_and_output_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-data-1","Section": "your data","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Learn how your data is protected.","checks_status": {"fail": 4,"pass": 3,"total": 13,"manual": 0}},"your-data-2": {"name": "Your Data-2","checks": {"elb_ssl_listeners": "FAIL","elb_logging_enabled": "FAIL","elbv2_ssl_listeners": "FAIL","vpc_flow_logs_enabled": "FAIL","ec2_instance_public_ip": "FAIL","elbv2_waf_acl_attached": "FAIL","efs_have_backup_enabled": "FAIL","s3_bucket_public_access": null,"s3_bucket_acl_prohibited": "FAIL","ec2_ebs_volume_encryption": "PASS","rds_snapshots_public_access": "PASS","s3_bucket_default_encryption": "PASS","rds_instance_no_public_access": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","redshift_cluster_audit_logging": null,"redshift_cluster_public_access": null,"cloudtrail_multi_region_enabled": "PASS","acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL","apigateway_restapi_logging_enabled": "PASS","s3_bucket_policy_public_write_access": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","awslambda_function_not_publicly_accessible": "PASS","dynamodb_tables_kms_cmk_encryption_enabled": null,"ec2_securitygroup_default_restrict_traffic": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL","apigateway_restapi_client_certificate_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_cloudwatch_logging_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","opensearch_service_domains_node_to_node_encryption_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_training_jobs_volume_and_output_encryption_enabled": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-data-2","Section": "your data","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Learn what is happening on your network, manage network and perimeter components, host and device components, data-at-rest and in-transit, and user behavior activities.","checks_status": {"fail": 18,"pass": 11,"total": 49,"manual": 0}},"your-data-3": {"name": "Your Data-3","checks": {"elbv2_waf_acl_attached": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-data-3","Section": "your data","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Domain name system protection.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"your-data-4": {"name": "Your Data-4","checks": {"efs_have_backup_enabled": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"rds_instance_deletion_protection": "FAIL","redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-data-4","Section": "your data","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Establish regular automated backups and redundancies of key systems.","checks_status": {"fail": 4,"pass": 1,"total": 8,"manual": 0}},"your-data-5": {"name": "Your Data-5","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "your-data-5","Section": "your data","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Leverage protections for backups, including physical security, encryption and offline copies.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"your-systems-1": {"name": "Your Systems-1","checks": {"ec2_elastic_ip_unassigned": "FAIL","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","ec2_instance_older_than_specific_days": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-systems-1","Section": "your systems","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Learn what is on your network. Maintain inventories of hardware and software assets to know what is in play and at-risk from attack.","checks_status": {"fail": 4,"pass": 0,"total": 4,"manual": 0}},"your-systems-2": {"name": "Your Systems-2","checks": {"ssm_managed_compliant_patching": "FAIL","redshift_cluster_automatic_upgrades": null,"rds_instance_minor_version_upgrade_enabled": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-systems-2","Section": "your systems","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Leverage automatic updates for all operating systems and third-party software.","checks_status": {"fail": 1,"pass": 1,"total": 3,"manual": 0}},"your-systems-3": {"name": "Your Systems-3","checks": {"elb_ssl_listeners": "FAIL","elb_logging_enabled": "FAIL","elbv2_ssl_listeners": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","iam_root_mfa_enabled": null,"rds_instance_multi_az": "FAIL","ec2_instance_public_ip": "FAIL","elbv2_waf_acl_attached": "FAIL","iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","efs_have_backup_enabled": "FAIL","s3_bucket_public_access": null,"kms_cmk_rotation_enabled": null,"ec2_ebs_volume_encryption": "PASS","elbv2_deletion_protection": "FAIL","iam_user_accesskey_unused": null,"ec2_ebs_default_encryption": "PASS","iam_password_policy_number": null,"iam_password_policy_symbol": null,"rds_instance_backup_enabled": "PASS","rds_snapshots_public_access": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"s3_bucket_default_encryption": "PASS","iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_root_hardware_mfa_enabled": null,"iam_rotate_access_key_90_days": null,"rds_instance_no_public_access": "PASS","efs_encryption_at_rest_enabled": "FAIL","iam_user_console_access_unused": null,"rds_instance_storage_encrypted": "FAIL","redshift_cluster_audit_logging": null,"redshift_cluster_public_access": null,"cloudtrail_multi_region_enabled": "PASS","rds_instance_deletion_protection": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","s3_bucket_secure_transport_policy": "FAIL","apigateway_restapi_logging_enabled": "PASS","apigateway_restapi_waf_acl_attached": "FAIL","iam_user_mfa_enabled_console_access": null,"redshift_cluster_automated_snapshot": null,"s3_bucket_policy_public_write_access": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"emr_cluster_master_nodes_no_public_ip": null,"iam_password_policy_minimum_length_14": null,"s3_account_level_public_access_blocks": null,"cloudtrail_log_file_validation_enabled": "FAIL","cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","secretsmanager_automatic_rotation_enabled": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","vpc_endpoint_connections_trust_boundaries": "FAIL","awslambda_function_not_publicly_accessible": "PASS","dynamodb_tables_kms_cmk_encryption_enabled": null,"ec2_securitygroup_default_restrict_traffic": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL","codebuild_project_user_controlled_buildspec": "PASS","apigateway_restapi_client_certificate_enabled": "FAIL","iam_inline_policy_no_administrative_privileges": null,"sagemaker_notebook_instance_encryption_enabled": null,"dynamodb_accelerator_cluster_encryption_enabled": null,"iam_no_custom_policy_permissive_role_assumption": null,"iam_aws_attached_policy_no_administrative_privileges": null,"opensearch_service_domains_cloudwatch_logging_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null,"iam_customer_attached_policy_no_administrative_privileges": null,"ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","opensearch_service_domains_node_to_node_encryption_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_training_jobs_volume_and_output_encryption_enabled": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-systems-3","Section": "your systems","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Implement security configurations for all hardware and software assets.","checks_status": {"fail": 25,"pass": 16,"total": 84,"manual": 0}},"your-surroundings-1": {"name": "Your Surroundings-1","checks": {"vpc_flow_logs_enabled": "FAIL","ec2_elastic_ip_unassigned": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-surroundings-1","Section": "your surroundings","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Learn who is on your network. Maintain inventories of network connections (user accounts, vendors, business partners, etc.).","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"your-surroundings-2": {"name": "Your Surroundings-2","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "your-surroundings-2","Section": "your surroundings","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Leverage multi-factor authentication for all users, starting with privileged, administrative and remote access users.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"your-surroundings-3": {"name": "Your Surroundings-3","checks": {"elbv2_ssl_listeners": "FAIL","iam_no_root_access_key": null,"iam_inline_policy_no_administrative_privileges": null,"iam_no_custom_policy_permissive_role_assumption": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "your-surroundings-3","Section": "your surroundings","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Grant access and admin permissions based on need-to-know and least privilege.","checks_status": {"fail": 1,"pass": 0,"total": 6,"manual": 0}},"your-surroundings-4": {"name": "Your Surroundings-4","checks": {"iam_password_policy_number": null,"iam_password_policy_symbol": null,"iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_password_policy_minimum_length_14": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "your-surroundings-4","Section": "your surroundings","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Leverage unique passwords for all user accounts.","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"your-crisis-response-2": {"name": "Your Crisis Response-2","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "your-crisis-response-2","Section": "your crisis response","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Lead development of an internal reporting structure to detect, communicate and contain attacks.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"booting-up-thing-to-do-first-1": {"name": "YBooting Up: Things to Do First-1","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "booting-up-thing-to-do-first-1","Section": "booting up thing to do first","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Lead development of an internal reporting structure to detect, communicate and contain attacks.","checks_status": {"fail": 2,"pass": 1,"total": 7,"manual": 0}},"booting-up-thing-to-do-first-2": {"name": "YBooting Up: Things to Do First-2","checks": {"iam_root_mfa_enabled": null,"iam_user_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "booting-up-thing-to-do-first-2","Section": "booting up thing to do first","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Require multi-factor authentication (MFA) for accessing your systems whenever possible. MFA should be required of all users, but start with privileged, administrative, and remote access users.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"booting-up-thing-to-do-first-3": {"name": "YBooting Up: Things to Do First-3","checks": {"ssm_managed_compliant_patching": "FAIL","redshift_cluster_automatic_upgrades": null,"rds_instance_minor_version_upgrade_enabled": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "booting-up-thing-to-do-first-1","Section": "booting up thing to do first","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Enable automatic updates whenever possible. Replace unsupported operating systems, applications and hardware. Test and deploy patches quickly.","checks_status": {"fail": 1,"pass": 1,"total": 3,"manual": 0}}},"requirements_passed": 4,"requirements_failed": 11,"requirements_manual": 1,"total_requirements": 16,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "089cf697-547a-4a34-a811-e7a19b78b9fd","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "aws_foundational_technical_review_aws","framework": "AWS-Foundational-Technical-Review","version": "","description": "The AWS Foundational Technical Review (FTR) assesses an AWS Partner's solution against a specific set of Amazon Web Services (AWS) best practices around security, performance, and operational processes that are most critical for customer success. Passing the FTR is required to qualify AWS Software Partners for AWS Partner Network (APN) programs such as AWS Competency and AWS Service Ready but any AWS Partner who offers a technology solution may request a FTR review through AWS Partner Central.","region": "eu-west-1","requirements": {"S3-001": {"name": "Review all Amazon S3 buckets to determine appropriate access levels","checks": {"s3_bucket_object_lock": "FAIL","s3_bucket_public_access": null,"s3_bucket_acl_prohibited": "FAIL","s3_bucket_kms_encryption": "FAIL","s3_bucket_public_list_acl": null,"s3_bucket_public_write_acl": null,"s3_bucket_default_encryption": "PASS","s3_bucket_secure_transport_policy": "FAIL","s3_bucket_level_public_access_block": "PASS","s3_bucket_policy_public_write_access": "PASS","s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "You must ensure that buckets that require public access have been reviewed to determine if public read or write access is needed and if appropriate controls are in place to control public access. When assigning access permissions, follow the principle of least privilege, an AWS best practice. For more information, refer to overview of managing access.","checks_status": {"fail": 5,"pass": 3,"total": 11,"manual": 0}},"ARC-001": {"name": "Use root user only by exception","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "The root user has unlimited access to your account and its resources, and using it only by exception helps protect your AWS resources. The AWS root user must not be used for everyday tasks, even administrative ones. Instead, adhere to the best practice of using the root user only to create your first AWS Identity and Access Management (IAM) user. Then securely lock away the root user credentials and use them to perform only a few accounts and service management tasks. To view the tasks that require you to sign in as the root user, see AWS Tasks That Require Root User. FTR does not require you to actively monitor root usage.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ARC-003": {"name": "Enable multi-factor authentication (MFA) on the root user for all AWS accounts","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Enabling MFA provides an additional layer of protection against unauthorized access to your account. To configure MFA for the root user, follow the instructions for enabling either a virtual MFA or hardware MFA device. If you are using AWS Organizations to create new accounts, the initial password for the root user is set to a random value that is never exposed to you. If you do not recover the password for the root user of these accounts, you do not need to enable MFA on them. For any accounts where you do have access to the root userās password, you must enable MFA","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"ARC-004": {"name": "Remove access keys for the root user","checks": {"iam_no_root_access_key": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Programmatic access to AWS APIs should never use the root user. It is best not to generate static an access key for the root user. If one already exists, you should transition any processes using that key to use temporary access keys from an AWS Identity and Access Management (IAM) role, or, if necessary, static access keys from an IAM user.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"ARC-005": {"name": "Develop incident management plans","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "An incident management plan is critical to respond, mitigate, and recover from the potential impact of security incidents. An incident management plan is a structured process for identifying, remediating, and responding in a timely matter to security incidents. An effective incident management plan must be continually iterated upon, remaining current with your cloud operations goal. For more information on developing incident management plan please see Develop incident management plans.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"BAR-001": {"name": "Configure automatic data backups","checks": {"backup_plans_exist": "PASS","backup_vaults_exist": null,"backup_vaults_encrypted": "PASS","efs_have_backup_enabled": "FAIL","backup_reportplans_exist": null,"rds_instance_backup_enabled": "PASS"},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "You must perform regular backups to a durable storage service. Backups ensure that you have the ability to recover from administrative, logical, or physical error scenarios. Configure backups to be taken automatically based on a periodic schedule, or by changes in the dataset. RDS instances, EBS volumes, DynamoDB tables, and S3 objects can all be configured for automatic backup. AWS Backup, AWS Marketplace solutions or third-party solutions can also be used. If objects in S3 bucket are write-once-read-many (WORM), compensating controls such as object lock can be used meet this requirement. If it is customersā responsibility to backup their data, it must be clearly stated in the documentation and the Partner must provide clear instructions on how to backup the data.","checks_status": {"fail": 1,"pass": 3,"total": 6,"manual": 0}},"BAR-002": {"name": "Periodically recover data to verify the integrity of your backup process","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "To confirm that your backup process meets your recovery time objectives (RTO) and recovery point objectives (RPO), run a recovery test on a regular schedule and after making significant changes to your cloud environment. For more information, refer to Getting Started - Backup and Restore with AWS.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-001": {"name": "Use cross-account roles to access customer AWS accounts","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Cross-account roles reduce the amount of sensitive information AWS Partners need to store for their customers.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-002": {"name": "Use an external ID with cross-account roles to access customer accounts","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "An external ID allows the user that is assuming the role to assert the circumstances in which they are operating. It also provides a way for the account owner to permit the role to be assumed only under specific circumstances. The primary function of the external ID is to address and prevent the confused deputy problem.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-003": {"name": "Deprecate any historical use of customer-provided IAM credentials","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "If your application provides legacy support for the use of static IAM credentials for cross-account access, the application's user interface and customer documentation must make it clear that this method is deprecated. Existing customers should be encouraged to switch to cross-account role based-access, and collection of credentials should be disabled for new customers.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-004": {"name": "Use a value you generate (not something provided by the customer) for the external ID","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "When configuring cross-account access using IAM roles, you must use a value you generate for the external ID, instead of one provided by the customer, to ensure the integrity of the cross-account role configuration. A partner-generated external ID ensures that malicious parties cannot impersonate a customer's configuration and enforces uniqueness and format consistency across all customers. If you are not generating an external ID today we recommend implementing a process that generates a random unique value (such as a Universally Unique Identifier) for the external ID that a customer uses to set up a cross-account role.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-005": {"name": "Ensure that all external IDs are unique.","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "The external IDs used must be unique across all customers. Re-using external IDs for different customers does not solve the confused deputy problem and runs the risk of customer A being able to view data of customer B by using the role ARN and the external ID of customer B. To resolve this, we recommend implementing a process that ensures a random unique value, such as a Universally Unique Identifier, is generated for the external ID that a customer would use to setup a cross account role.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-006": {"name": "Provide read-only access to external ID to customers","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Customers must not be able to set or influence external IDs. When the external ID is editable, it is possible for one customer to impersonate the configuration of another. For example, when the external ID is editable, customer A can create a cross account role setup using customer Bās role ARN and external ID, granting customer A access to customer Bās data. Remediation of this item involves making the external ID a view-only field, ensuring that the external ID cannot be changed to impersonate the setup of another customer.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"CAA-007": {"name": "Provide guidance or an automated setup mechanism (for example, an AWS CloudFormation template) for creating cross-account roles with the minimum required privileges","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "The policy created for cross-account access in customer accounts must follow the principle of least privilege. The AWS Partner must provide a role-policy document or an automated setup mechanism (for example, an AWS CloudFormation template) for the customers to use to ensure that the roles are created with minimum required privileges. For more information, refer to the AWS Partner Network (APN) blog posts.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-001": {"name": "Enable multi-factor authentication (MFA) for all Human Identities with AWS access","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_hardware_mfa_enabled": null,"iam_administrator_access_with_mfa": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "You must require any human identities to authenticate using MFA before accessing your AWS accounts. Typically, this means enabling MFA within your corporate identity provider. If you have existing legacy IAM users you must enable MFA for console access for those principals as well. Enabling MFA for IAM users provides an additional layer of security. With MFA, users have a device that generates a unique authentication code (a one-time password, or OTP). Users must provide both their normal credentials (user name and password) and the OTP. The MFA device can either be a special piece of hardware, or it can be a virtual device (for example, it can run in an app on a smartphone). Please note that machine identities do not require MFA.","checks_status": {"fail": 0,"pass": 0,"total": 5,"manual": 0}},"IAM-002": {"name": "Monitor and secure static AWS Identity and Access Management (IAM) credentials","checks": {"guardduty_is_enabled": "PASS","iam_user_accesskey_unused": null,"iam_rotate_access_key_90_days": null,"guardduty_no_high_severity_findings": "FAIL","iam_user_with_temporary_credentials": null},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Use temporary IAM credentials retrieved by assuming a role whenever possible. In cases where it is infeasible to use IAM roles, implement the following controls to reduce the risk these credentials are misused: Rotate IAM access keys regularly (recommended at least every 90 days). Maintain an inventory of all static keys and where they are used and remove unused access keys. Implement monitoring of AWS CloudTrail logs to detect anomalous activity or other potential misuse (e.g. using AWS GuardDuty.) Define a runbook or SOP for revoking credentials in the event you detect misuse.","checks_status": {"fail": 1,"pass": 1,"total": 5,"manual": 0}},"IAM-003": {"name": "Use strong password policy","checks": {"iam_password_policy_number": null,"iam_password_policy_symbol": null,"iam_password_policy_reuse_24": null,"iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_password_policy_minimum_length_14": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Enforce a strong password policy, and educate users to avoid common or re-used passwords. For IAM users, you can create a password policy for your account on the Account Settings page of the IAM console. You can use the password policy to define password requirements, such as minimum length and whether it requires non-alphabetic characters, and so on. For more information, see Setting an Account Password Policy for IAM users.","checks_status": {"fail": 0,"pass": 0,"total": 7,"manual": 0}},"IAM-004": {"name": "Create individual identities (no shared credentials) for anyone who needs AWS access","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Create individual entities and give unique security credentials and permissions to each user accessing your account. With individual entities and no shared credentials, you can audit the activity of each user.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-005": {"name": "Use IAM roles and its temporary security credentials to provide access to third parties.","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Do not provision IAM users and share those credentials with people outside of your organization. Any external services that need to make AWS API calls against your account (for example, a monitoring solution that accesses your account's AWS CloudWatch metrics) must use a cross-account role. For more information, refer to Providing access to AWS accounts owned by third parties.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-006": {"name": "Grant least privilege access","checks": {"iam_policy_attached_only_to_group_or_roles": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "You must follow the standard security advice of granting least privilege. Grant only the access that identities require by allowing access to specific actions on specific AWS resources under specific conditions. Rely on groups and identity attributes to dynamically set permissions at scale, rather than defining permissions for individual users. For example, you can allow a group of developers access to manage only resources for their project. This way, when a developer is removed from the group, access for the developer is revoked everywhere that group was used for access control, without requiring any changes to the access policies.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"IAM-007": {"name": "Manage access based on life cycle","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Integrate access controls with operator and application lifecycle and your centralized federation provider and IAM. For example, remove a userās access when they leave the organization or change roles.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-008": {"name": "Audit identities quarterly","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Auditing the identities that are configured in your identity provider and IAM helps ensure that only authorized identities have access to your workload. For example, remove people that leave the organization, and remove cross-account roles that are no longer required. Have a process in place to periodically audit permissions to the services accessed by an IAM entity. This helps you identify the policies you needto modify to remove any unused permissions. For more information, see Refining permissions in AWS using last accessed information.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-009": {"name": "Do not embed credentials in application code","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Ensure that all credentials used by your applications (for example, IAM access keys and database passwords) are never included in your application's source code or committed to source control in any way.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-001": {"name": "Define a Recovery Point Objective (RPO)","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "To confirm that your backup process meets your recovery time objectives (RTO) and recovery point objectives (RPO), run a recovery test on a regular schedule and after making significant changes to your cloud environment. For more information, refer to Getting Started - Backup and Restore with AWS.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-002": {"name": "Establish a Recovery Time Objective (RTO)","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Define an RTO that meets your organizationās needs and expectations. RTO is the maximum acceptable delay your organization will accept between the interruption and restoration of service.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-004": {"name": "Resiliency Testing","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Test resiliency to ensure that RTO and RPO are met, both periodically (minimum every 12 months) and after major updates. The resiliency test must include accidental data loss, instance failures, and Availability Zone (AZ) failures. At least one resilience test that meets RTO and RPO requirements must be completed prior to FTR approval. You can use AWS Resilience Hub to test and verify your workloads to see if it meets its resilience target. AWS Resilience Hub works with AWS Fault Injection Service (AWS FIS) , a chaos engineering service, to provide fault-injection simulations of real-world failures to validate the application recovers within the resilience targets you defined. AWS Resilience Hub also provides API operations for you to integrate its resilience assessment and testing into your CI/CD pipelines for ongoing resilience validation. Including resilience validation in CI/CD pipelines helps make sure that changes to the workloadās underlying infrastructure don't compromise resilience.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-005": {"name": "Communicate customer responsibilities for resilience","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Clearly define your customersā responsibility for backup, recovery, and availability. At a minimum, your product documentation or customer agreements should cover the following: Responsibility the customer has for backing up the data stored in your solution. Instructions for backing up data or configuring optional features in your product for data protection, if applicable. Options customers have for configuring the availability of your product.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-006": {"name": "Architect your product to meet availability targets and uptime service level agreements (SLAs)","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "If you publish or privately agree to availability targets or uptime SLAs, ensure that your architecture and operational processes are designed to support them. Additionally, provide clear guidance to customers on any configuration required to achieve the targets or SLAs.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"RES-007": {"name": "Define a customer communication plan for outages","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Establish a plan for communicating information about system outages to your customers both during and after incidents. Your communication should not include any data that was provided by AWS under a non-disclosure agreement (NDA).","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"SUP-001": {"name": "Subscribe to the AWS Business Support tier (or higher) for all production AWS accounts or have an action plan to handle issues which require help from AWS Support","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Partner-hosted FTR requirements","Service": null,"SubGroup": null,"SubSection": null}],"description": "It is recommended that you subscribe to the AWS Business Support tier or higher (including AWS Partner-Led Support) for all of your AWS production accounts. For more information, refer to Compare AWS Support Plans. If you don't have premium support, you must have an action plan to handle issues which require help from AWS Support. AWS Support provides a mix of tools and technology, people, and programs designed to proactively help you optimize performance, lower costs, and innovate faster. AWS Business Support provides additional benefits including access to AWS Trusted Advisor and AWS Personal Health Dashboard and faster response times.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ACOM-001": {"name": "Configure AWS account contacts","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "If an account is not managed by AWS Organizations, alternate account contacts help AWS get in contact with the appropriate personnel if needed. Configure the accountās alternate contacts to point to a group rather than an individual. For example, create separate email distribution lists for billing, operations, and security and configure these as Billing, Security, and Operations contacts in each active AWS account. This ensures that multiple people will receive AWS notifications and be able to respond, even if someone is on vacation, changes roles, or leaves the company.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ACOM-002": {"name": "Set account contact information including the root user email address to email addresses and phone numbers owned by your company","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Using company owned email addresses and phone numbers for contact information enables you to access them even if the individuals whom they belong to are no longer with your organization","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"HOST-001": {"name": "Confirm your hosting model","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Partner-hosted FTR requirements","Service": null,"SubGroup": null,"SubSection": null}],"description": "To use this FTR checklist you must host all critical application components on AWS. You may use external providers for edge services such as content delivery networks (CDNs) or domain name system (DNS), or corporate identity providers. If you are using any edge services outside AWS, please specify them in the self-assessment.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-0010": {"name": "Store secrets securely.","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Encrypt all secrets in transit and at rest, define fine-grained access controls that only allow access to specific identities, and log access to secrets in an audit log. We recommend you use a purpose-built secret management service such as AWS Secrets Manager, AWS Systems Manager Parameter Store, or an AWS Partner solution, but internally developed solutions that meet these requirements are also acceptable.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-0011": {"name": "Encrypt all end user/customer credentials and hash passwords at rest.","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "If you are storing end user/customer credentials in a database that you manage, encrypt credentials at rest and hash passwords. As an alternative, AWS recommends using a user-identity synchronization service, such as Amazon Cognito or an equivalent AWS Partner solution.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"IAM-0012": {"name": "Use temporary credentials","checks": {"iam_root_mfa_enabled": null,"iam_user_accesskey_unused": null,"iam_root_hardware_mfa_enabled": null,"iam_rotate_access_key_90_days": null,"iam_user_hardware_mfa_enabled": null,"iam_administrator_access_with_mfa": null,"iam_role_administratoraccess_policy": null,"iam_user_mfa_enabled_console_access": null,"iam_user_with_temporary_credentials": null,"iam_policy_attached_only_to_group_or_roles": null,"iam_role_cross_account_readonlyaccess_policy": null,"iam_role_cross_service_confused_deputy_prevention": null},"status": "PASS","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Use temporary security credentials to access AWS resources. For machine identities within AWS (for example, Amazon Elastic Compute Cloud (Amazon EC2) instances or AWS Lambda functions), always use IAM roles to acquire temporary security credentials. For machine identities running outside of AWS, use IAM Roles Anywhere or securely store static AWS access keys that are only used to assume an IAM role.For human identities, use AWS IAM Identity Center or other identity federation solutions where possible. If you must use static AWS access keys for human users, require MFA for all access, including the AWS Management Console, and AWS Command Line Interface (AWS CLI).","checks_status": {"fail": 0,"pass": 0,"total": 13,"manual": 0}},"RCVP-001": {"name": "Establish a process to ensure that all required compliance standards are met","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "If you advertise that your product meets specific compliance standards, you must have an internal process for ensuring compliance. Examples of compliance standards include Payment Card Industry Data Security Standard (PCI DSS) PCI DSS, Federal Risk and Authorization Management Program (FedRAMP)FedRAMP, and U.S. Health Insurance Portability and Accountability Act (HIPAA)HIPAA. Applicable compliance standards are determined by various factors, such as what types of data the solution stores or transmits and which geographic regions the solution supports.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"SDAT-001": {"name": "Identify sensitive data (for example, Personally Identifiable Information (PII) and Protected Health Information (PHI))","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Data classification enables you to determine which data needs to be protected and how. Based on the workload and the data it processes, identify the data that is not common public knowledge.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"SDAT-002": {"name": "Encrypt all sensitive data at rest","checks": {"athena_workgroup_encryption": null,"efs_encryption_at_rest_enabled": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","dynamodb_tables_kms_cmk_encryption_enabled": null,"dynamodb_accelerator_cluster_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Encryption maintains the confidentiality of sensitive data even when it gets stolen or the network through which it is transmitted becomes compromised.","checks_status": {"fail": 3,"pass": 0,"total": 7,"manual": 0}},"SDAT-003": {"name": "Only use protocols with encryption when transmitting sensitive data outside of your VPC","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Encryption maintains data confidentiality even when the network through which it is transmitted becomes compromised.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"WAFR-001": {"name": "Conduct periodic architecture reviews (minimum once every year)","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Partner-hosted FTR requirements","Service": null,"SubGroup": null,"SubSection": null}],"description": "Conduct periodic architecture reviews of your production workload (at least once per year) using a documented architectural standard that includes AWS-specific best practices. If you have an internally defined standard for your AWS workloads, we recommend you use it for these reviews. If you do not have an internal standard, we recommend you use the AWS Well-Architected Framework.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"WAFR-002": {"name": "Review the AWS Shared Responsibility Models for Security and Resiliency","checks": {},"status": "PASS","attributes": [{"Type": "Manual","ItemId": null,"Section": "Partner-hosted FTR requirements","Service": null,"SubGroup": null,"SubSection": null}],"description": "Review the AWS Shared Responsibility Model for Security and the AWS Shared Responsibility Model for Resiliency. Ensure that your productās architecture and operational processes address the customer responsibilities defined in these models. We recommend you to use AWS Resilience Hub to ensure your workload resiliency posture meets your targets and to provide you with operational procedures you may use to address the customer responsibilities.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"NETSEC-001": {"name": "Implement the least permissive rules for all Amazon EC2 security groups","checks": {"ec2_ami_public": null,"ec2_instance_public_ip": "FAIL","ec2_securitygroup_not_used": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_securitygroup_with_many_ingress_egress_rules": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601": "PASS"},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "All Amazon EC2 security groups should restrict access to the greatest degree possible. At a minimum, do the following: Ensure that no security groups allow ingress from 0.0.0.0/0 to port 22 or 3389 (CIS 5.2) Ensure that the default security group of every VPC restricts all traffic (CIS 5.3/Security Control EC2.2)","checks_status": {"fail": 3,"pass": 16,"total": 20,"manual": 0}},"NETSEC-002": {"name": "Restrict resources in public subnets","checks": {"vpc_subnet_no_public_ip_by_default": "FAIL","vpc_subnet_separate_private_public": "FAIL","vpc_endpoint_connections_trust_boundaries": "FAIL","workspaces_vpc_2private_1public_subnets_nat": null,"vpc_endpoint_services_allowed_principals_trust_boundaries": null},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Do not place resources in public subnets of your VPC unless they must receive network traffic from public sources. Public subnets are subnets associated with a route table that has a route to an internet gateway.","checks_status": {"fail": 3,"pass": 0,"total": 5,"manual": 0}},"SECOPS-001": {"name": "Perform vulnerability management","checks": {"inspector2_is_enabled": "FAIL","inspector2_active_findings_exist": "FAIL","guardduty_no_high_severity_findings": "FAIL","accessanalyzer_enabled_without_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": "Automated","ItemId": null,"Section": "Architectural and Operational Controls","Service": null,"SubGroup": null,"SubSection": null}],"description": "Define a mechanism and frequency to scan and patch for vulnerabilities in your dependencies, and in your operating systems to help protect against new threats. Scan and patch your dependencies, and your operating systems on a defined schedule. Software vulnerability management is essential to keeping your system secure from threat actors. Embedding vulnerability assessments early into your continuous integration/continuous delivery (CI/CD) pipeline allows you to prioritize remediation of any security vulnerabilities detected. The solution you need to achieve this varies according to the AWS services that you are consuming. To check for vulnerabilities in software running in Amazon EC2 instances, you can add Amazon Inspector to your pipeline to cause your build to fail if Inspector detects vulnerabilities. You can also use open source products such as OWASP Dependency-Check, Snyk, OpenVAS, package managers and AWS Partner tools for vulnerability management.","checks_status": {"fail": 4,"pass": 0,"total": 4,"manual": 0}}},"requirements_passed": 6,"requirements_failed": 7,"requirements_manual": 32,"total_requirements": 45,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "1491ce35-3d2b-4cf6-a56d-b18b391d5623","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "nist_800_171_revision_2_aws","framework": "NIST-800-171-Revision-2","version": "","description": "The cybersecurity controls within NIST 800-171 safeguard CUI in the IT networks of government contractors and subcontractors. It defines the practices and procedures that government contractors must adhere to when their networks process or store CUI. NIST 800-171 only applies to those parts of a contractorās network where CUI is present.","region": "eu-west-1","requirements": {"3_1_1": {"name": "3.1.1 Limit system access to authorized users, processes acting on behalf of authorized users, and devices (including other systems)","checks": {"iam_root_mfa_enabled": null,"ec2_instance_public_ip": "FAIL","iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"iam_user_accesskey_unused": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"ec2_instance_profile_attached": "PASS","iam_root_hardware_mfa_enabled": null,"rds_instance_no_public_access": "PASS","iam_user_console_access_unused": null,"redshift_cluster_public_access": null,"eks_cluster_not_publicly_accessible": null,"iam_user_mfa_enabled_console_access": null,"s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_1","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Access control policies (e.g., identity or role-based policies, control matrices, and cryptography) control access between active entities or subjects (i.e., users or processes acting on behalf of users) and passive entities or objects (e.g., devices, files, records, and domains) in systems. Access enforcement mechanisms can be employed at the application and service level to provide increased information security. Other systems include systems internal and external to the organization. This requirement focuses on account management for systems and applications. The definition of and enforcement of access authorizations, other than those determined by account type (e.g., privileged verses non-privileged) are addressed in requirement 3.1.2.","checks_status": {"fail": 3,"pass": 7,"total": 28,"manual": 0}},"3_1_2": {"name": "3.1.2 Limit system access to the types of transactions and functions that authorized users are permitted to execute","checks": {"iam_root_mfa_enabled": null,"ec2_instance_public_ip": "FAIL","iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"iam_user_accesskey_unused": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"ec2_instance_profile_attached": "PASS","iam_root_hardware_mfa_enabled": null,"rds_instance_no_public_access": "PASS","iam_user_console_access_unused": null,"redshift_cluster_public_access": null,"eks_cluster_not_publicly_accessible": null,"iam_user_mfa_enabled_console_access": null,"s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_2","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations may choose to define access privileges or other attributes by account, by type of account, or a combination of both. System account types include individual, shared, group, system, anonymous, guest, emergency, developer, manufacturer, vendor, and temporary. Other attributes required for authorizing access include restrictions on time-of-day, day-of-week, and point-oforigin. In defining other account attributes, organizations consider system-related requirements (e.g., system upgrades scheduled maintenance,) and mission or business requirements, (e.g., time zone differences, customer requirements, remote access to support travel requirements).","checks_status": {"fail": 3,"pass": 7,"total": 28,"manual": 0}},"3_1_3": {"name": "3.1.3 Control the flow of CUI in accordance with approved authorizations","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"eks_cluster_not_publicly_accessible": null,"s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_3","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Information flow control regulates where information can travel within a system and between systems (versus who can access the information) and without explicit regard to subsequent accesses to that information. Flow control restrictions include the following: keeping exportcontrolled information from being transmitted in the clear to the Internet; blocking outside traffic that claims to be from within the organization; restricting requests to the Internet that are not from the internal web proxy server; and limiting information transfers between organizations based on data structures and content. Organizations commonly use information flow control policies and enforcement mechanisms to control the flow of information between designated sources and destinations (e.g., networks, individuals, and devices) within systems and between interconnected systems. Flow control is based on characteristics of the information or the information path. Enforcement occurs in boundary protection devices (e.g., gateways, routers, guards, encrypted tunnels, firewalls) that employ rule sets or establish configuration settings that restrict system services, provide a packetfiltering capability based on header information, or message-filtering capability based on message content (e.g., implementing key word searches or using document characteristics). Organizations also consider the trustworthiness of filtering and inspection mechanisms (i.e., hardware, firmware, and software components) that are critical to information flow enforcement. Transferring information between systems representing different security domains with different security policies introduces risk that such transfers violate one or more domain security policies. In such situations, information owners or stewards provide guidance at designated policy enforcement points between interconnected systems. Organizations consider mandating specific architectural solutions when required to enforce specific security policies. Enforcement includes: prohibiting information transfers between interconnected systems (i.e., allowing access only); employing hardware mechanisms to enforce one-way information flows; and implementing trustworthy regrading mechanisms to reassign security attributes and security labels.","checks_status": {"fail": 3,"pass": 6,"total": 17,"manual": 0}},"3_1_4": {"name": "3.1.4 Separate the duties of individuals to reduce the risk of malevolent activity without collusion","checks": {"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_user_console_access_unused": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_1_4","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Separation of duties addresses the potential for abuse of authorized privileges and helps to reduce the risk of malevolent activity without collusion. Separation of duties includes dividing mission functions and system support functions among different individuals or roles; conducting system support functions with different individuals (e.g., configuration management, quality assurance and testing, system management, programming, and network security); and ensuring that security personnel administering access control functions do not also administer audit functions. Because separation of duty violations can span systems and application domains, organizations consider the entirety of organizational systems and system components when developing policy on separation of duties.","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"3_1_5": {"name": "3.1.5 Employ the principle of least privilege, including for specific security functions and privileged accounts","checks": {"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_user_console_access_unused": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_1_5","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations employ the principle of least privilege for specific duties and authorized accesses for users and processes. The principle of least privilege is applied with the goal of authorized privileges no higher than necessary to accomplish required organizational missions or business functions. Organizations consider the creation of additional processes, roles, and system accounts as necessary, to achieve least privilege. Organizations also apply least privilege to the development, implementation, and operation of organizational systems. Security functions include establishing system accounts, setting events to be logged, setting intrusion detection parameters, and configuring access authorizations (i.e., permissions, privileges). Privileged accounts, including super user accounts, are typically described as system administrator for various types of commercial off-the-shelf operating systems. Restricting privileged accounts to specific personnel or roles prevents day-to-day users from having access to privileged information or functions. Organizations may differentiate in the application of this requirement between allowed privileges for local accounts and for domain accounts provided organizations retain the ability to control system configurations for key security parameters and as otherwise necessary to sufficiently mitigate risk.","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"3_1_6": {"name": "3.1.6 Use non-privileged accounts or roles when accessing nonsecurity functions","checks": {"iam_no_root_access_key": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_1_6","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "This requirement limits exposure when operating from within privileged accounts or roles. The inclusion of roles addresses situations where organizations implement access control policies such as role-based access control and where a change of role provides the same degree of assurance in the change of access authorizations for the user and all processes acting on behalf of the user as would be provided by a change between a privileged and non-privileged account.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"3_1_7": {"name": "3.1.7 Prevent non-privileged users from executing privileged functions and capture the execution of such functions in audit logs","checks": {"iam_no_root_access_key": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_1_7","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Privileged functions include establishing system accounts, performing system integrity checks, conducting patching operations, or administering cryptographic key management activities. Nonprivileged users are individuals that do not possess appropriate authorizations. Circumventing intrusion detection and prevention mechanisms or malicious code protection mechanisms are examples of privileged functions that require protection from non-privileged users. Note that this requirement represents a condition to be achieved by the definition of authorized privileges in 3.1.2. Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Logging the use of privileged functions is one way to detect such misuse, and in doing so, help mitigate the risk from insider threats and the advanced persistent threat.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"3_3_1": {"name": "3.3.1 Create and retain system audit logs and records to the extent needed to enable the monitoring, analysis, investigation, and reporting of unlawful or unauthorized system activity","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_3_1","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "An event is any observable occurrence in a system, which includes unlawful or unauthorized system activity. Organizations identify event types for which a logging functionality is needed as those events which are significant and relevant to the security of systems and the environments in which those systems operate to meet specific and ongoing auditing needs. Event types can include password changes, failed logons or failed accesses related to systems, administrative privilege usage, or third-party credential usage. In determining event types that require logging, organizations consider the monitoring and auditing appropriate for each of the CUI security requirements. Monitoring and auditing requirements can be balanced with other system needs. For example, organizations may determine that systems must have the capability to log every file access both successful and unsuccessful, but not activate that capability except for specific circumstances due to the potential burden on system performance. Audit records can be generated at various levels of abstraction, including at the packet level as information traverses the network. Selecting the appropriate level of abstraction is a critical aspect of an audit logging capability and can facilitate the identification of root causes to problems. Organizations consider in the definition of event types, the logging necessary to cover related events such as the steps in distributed, transaction-based processes (e.g., processes that are distributed across multiple organizations) and actions that occur in service-oriented or cloudbased architectures. Audit record content that may be necessary to satisfy this requirement includes time stamps, source and destination addresses, user or process identifiers, event descriptions, success or fail indications, filenames involved, and access control or flow control rules invoked. Event outcomes can include indicators of event success or failure and event-specific results (e.g., the security state of the system after the event occurred). Detailed information that organizations may consider in audit records includes full text recording of privileged commands or the individual identities of group account users. Organizations consider limiting the additional audit log information to only that information explicitly needed for specific audit requirements. This facilitates the use of audit trails and audit logs by not including information that could potentially be misleading or could make it more difficult to locate information of interest. Audit logs are reviewed and analyzed as often as needed to provide important information to organizations to facilitate risk-based decision making.","checks_status": {"fail": 7,"pass": 4,"total": 14,"manual": 0}},"3_3_2": {"name": "3.3.2 Ensure that the actions of individual system users can be uniquely traced to those users, so they can be held accountable for their actions","checks": {"guardduty_is_enabled": "PASS","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_3_2","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "This requirement ensures that the contents of the audit record include the information needed to link the audit event to the actions of an individual to the extent feasible. Organizations consider logging for traceability including results from monitoring of account usage, remote access, wireless connectivity, mobile device connection, communications at system boundaries, configuration settings, physical access, nonlocal maintenance, use of maintenance tools, temperature and humidity, equipment delivery and removal, system component inventory, use of mobile code, and use of Voice over Internet Protocol (VoIP).","checks_status": {"fail": 3,"pass": 3,"total": 9,"manual": 0}},"3_3_3": {"name": "3.3.3 Review and update logged events","checks": {"vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_3_3","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The intent of this requirement is to periodically re-evaluate which logged events will continue to be included in the list of events to be logged. The event types that are logged by organizations may change over time. Reviewing and updating the set of logged event types periodically is necessary to ensure that the current set remains necessary and sufficient.","checks_status": {"fail": 4,"pass": 2,"total": 9,"manual": 0}},"3_3_4": {"name": "3.3.4 Alert in the event of an audit logging process failure","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_3_4","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Audit logging process failures include software and hardware errors, failures in the audit record capturing mechanisms, and audit record storage capacity being reached or exceeded. This requirement applies to each audit record data storage repository (i.e., distinct system component where audit records are stored), the total audit record storage capacity of organizations (i.e., all audit record data storage repositories combined), or both.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"3_3_5": {"name": "3.3.5 Correlate audit record review, analysis, and reporting processes for investigation and response to indications of unlawful, unauthorized, suspicious, or unusual activity","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_3_5","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Correlating audit record review, analysis, and reporting processes helps to ensure that they do not operate independently, but rather collectively. Regarding the assessment of a given organizational system, the requirement is agnostic as to whether this correlation is applied at the system level or at the organization level across all systems.","checks_status": {"fail": 1,"pass": 2,"total": 3,"manual": 0}},"3_3_8": {"name": "3.3.8 Protect audit information and audit logging tools from unauthorized access, modification, and deletion","checks": {"s3_bucket_public_access": null,"s3_bucket_object_versioning": "FAIL","s3_bucket_default_encryption": "PASS","cloudtrail_kms_encryption_enabled": "FAIL","s3_bucket_policy_public_write_access": "PASS","s3_account_level_public_access_blocks": null,"cloudtrail_log_file_validation_enabled": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_3_8","Section": "3.3 Audit and Accountability","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Audit information includes all information (e.g., audit records, audit log settings, and audit reports) needed to successfully audit system activity. Audit logging tools are those programs and devices used to conduct audit and logging activities. This requirement focuses on the technical protection of audit information and limits the ability to access and execute audit logging tools to authorized individuals. Physical protection of audit information is addressed by media protection and physical and environmental protection requirements.","checks_status": {"fail": 4,"pass": 2,"total": 8,"manual": 0}},"3_4_1": {"name": "3.4.1 Establish and maintain baseline configurations and inventories of organizational systems (including hardware, software, firmware, and documentation) throughout the respective system development life cycles","checks": {"ec2_elastic_ip_unassigned": "FAIL","elbv2_deletion_protection": "FAIL","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","cloudtrail_multi_region_enabled": "PASS","ec2_instance_older_than_specific_days": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_4_1","Section": "3.4 Configuration Management","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Baseline configurations are documented, formally reviewed, and agreed-upon specifications for systems or configuration items within those systems. Baseline configurations serve as a basis for future builds, releases, and changes to systems. Baseline configurations include information about system components (e.g., standard software packages installed on workstations, notebook computers, servers, network components, or mobile devices; current version numbers and update and patch information on operating systems and applications; and configuration settings and parameters), network topology, and the logical placement of those components within the system architecture. Baseline configurations of systems also reflect the current enterprise architecture. Maintaining effective baseline configurations requires creating new baselines as organizational systems change over time. Baseline configuration maintenance includes reviewing and updating the baseline configuration when changes are made based on security risks and deviations from the established baseline configuration Organizations can implement centralized system component inventories that include components from multiple organizational systems. In such situations, organizations ensure that the resulting inventories include system-specific information required for proper component accountability (e.g., system association, system owner). Information deemed necessary for effective accountability of system components includes hardware inventory specifications, software license information, software version numbers, component owners, and for networked components or devices, machine names and network addresses. Inventory specifications include manufacturer, device type, model, serial number, and physical location.","checks_status": {"fail": 6,"pass": 1,"total": 7,"manual": 0}},"3_4_2": {"name": "3.4.2 Establish and enforce security configuration settings for information technology products employed in organizational systems","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","ec2_instance_older_than_specific_days": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_4_2","Section": "3.4 Configuration Management","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Configuration settings are the set of parameters that can be changed in hardware, software, or firmware components of the system that affect the security posture or functionality of the system. Information technology products for which security-related configuration settings can be defined include mainframe computers, servers, workstations, input and output devices (e.g., scanners, copiers, and printers), network components (e.g., firewalls, routers, gateways, voice and data switches, wireless access points, network appliances, sensors), operating systems, middleware, and applications. Security parameters are those parameters impacting the security state of systems including the parameters required to satisfy other security requirements. Security parameters include: registry settings; account, file, directory permission settings; and settings for functions, ports, protocols, and remote connections. Organizations establish organization-wide configuration settings and subsequently derive specific configuration settings for systems. The established settings become part of the systems configuration baseline. Common secure configurations (also referred to as security configuration checklists, lockdown and hardening guides, security reference guides, security technical implementation guides) provide recognized, standardized, and established benchmarks that stipulate secure configuration settings for specific information technology platforms/products and instructions for configuring those system components to meet operational requirements. Common secure configurations can be developed by a variety of organizations including information technology product developers, manufacturers, vendors, consortia, academia, industry, federal agencies, and other organizations in the public and private sectors.","checks_status": {"fail": 3,"pass": 0,"total": 3,"manual": 0}},"3_4_6": {"name": "3.4.6 Employ the principle of least functionality by configuring organizational systems to provide only essential capabilities","checks": {"iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"ec2_instance_managed_by_ssm": "FAIL","rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"redshift_cluster_public_access": null,"ssm_managed_compliant_patching": "FAIL","s3_bucket_policy_public_write_access": "PASS","s3_account_level_public_access_blocks": null,"ec2_securitygroup_default_restrict_traffic": "FAIL","iam_policy_attached_only_to_group_or_roles": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_4_6","Section": "3.4 Configuration Management","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Systems can provide a wide variety of functions and services. Some of the functions and services routinely provided by default, may not be necessary to support essential organizational missions, functions, or operations. It is sometimes convenient to provide multiple services from single system components. However, doing so increases risk over limiting the services provided by any one component. Where feasible, organizations limit component functionality to a single function per component. Organizations review functions and services provided by systems or components of systems, to determine which functions and services are candidates for elimination. Organizations disable unused or unnecessary physical and logical ports and protocols to prevent unauthorized connection of devices, transfer of information, and tunneling. Organizations can utilize network scanning tools, intrusion detection and prevention systems, and end-point protections such as firewalls and host-based intrusion detection systems to identify and prevent the use of prohibited functions, ports, protocols, and services.","checks_status": {"fail": 3,"pass": 3,"total": 15,"manual": 0}},"3_4_7": {"name": "3.4.7 Restrict, disable, or prevent the use of nonessential programs, functions, ports, protocols, and services","checks": {"ec2_networkacl_allow_ingress_any_port": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_4_7","Section": "3.4 Configuration Management","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Restricting the use of nonessential software (programs) includes restricting the roles allowed to approve program execution; prohibiting auto-execute; program blacklisting and whitelisting; or restricting the number of program instances executed at the same time. The organization makes a security-based determination which functions, ports, protocols, and/or services are restricted. Bluetooth, File Transfer Protocol (FTP), and peer-to-peer networking are examples of protocols organizations consider preventing the use of, restricting, or disabling.","checks_status": {"fail": 2,"pass": 1,"total": 4,"manual": 0}},"3_4_9": {"name": "3.4.9 Control and monitor user-installed software","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_4_9","Section": "3.4 Configuration Management","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Users can install software in organizational systems if provided the necessary privileges. To maintain control over the software installed, organizations identify permitted and prohibited actions regarding software installation through policies. Permitted software installations include updates and security patches to existing software and applications from organization-approved 'app stores.' Prohibited software installations may include software with unknown or suspect pedigrees or software that organizations consider potentially malicious. The policies organizations select governing user-installed software may be organization-developed or provided by some external entity. Policy enforcement methods include procedural methods, automated methods, or both.","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"3_5_2": {"name": "3.5.2 Authenticate (or verify) the identities of users, processes, or devices, as a prerequisite to allowing access to organizational systems","checks": {"iam_root_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_2","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Individual authenticators include the following: passwords, key cards, cryptographic devices, and one-time password devices. Initial authenticator content is the actual content of the authenticator, for example, the initial password. In contrast, the requirements about authenticator content include the minimum password length. Developers ship system components with factory default authentication credentials to allow for initial installation and configuration. Default authentication credentials are often well known, easily discoverable, and present a significant security risk. Systems support authenticator management by organization-defined settings and restrictions for various authenticator characteristics including minimum password length, validation time window for time synchronous one-time tokens, and number of allowed rejections during the verification stage of biometric authentication. Authenticator management includes issuing and revoking, when no longer needed, authenticators for temporary access such as that required for remote maintenance. Device authenticators include certificates and passwords.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"3_5_3": {"name": "3.5.3 Use multifactor authentication for local and network access to privileged accounts and for network access to non-privileged accounts","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_3","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Multifactor authentication requires the use of two or more different factors to authenticate. The factors are defined as something you know (e.g., password, personal identification number [PIN]); something you have (e.g., cryptographic identification device, token); or something you are (e.g., biometric). Multifactor authentication solutions that feature physical authenticators include hardware authenticators providing time-based or challenge-response authenticators and smart cards. In addition to authenticating users at the system level (i.e., at logon), organizations may also employ authentication mechanisms at the application level, when necessary, to provide increased information security. Access to organizational systems is defined as local access or network access. Local access is any access to organizational systems by users (or processes acting on behalf of users) where such access is obtained by direct connections without the use of networks. Network access is access to systems by users (or processes acting on behalf of users) where such access is obtained through network connections (i.e., nonlocal accesses). Remote access is a type of network access that involves communication through external networks. The use of encrypted virtual private networks for connections between organization-controlled and non-organization controlled endpoints may be treated as internal networks with regard to protecting the confidentiality of information.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"3_5_5": {"name": "3.5.5 Prevent reuse of identifiers for a defined period","checks": {"iam_password_policy_reuse_24": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_5","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Identifiers are provided for users, processes acting on behalf of users, or devices (3.5.1). Preventing reuse of identifiers implies preventing the assignment of previously used individual, group, role, or device identifiers to different individuals, groups, roles, or devices.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"3_5_6": {"name": "3.5.6 Disable identifiers after a defined period of inactivity","checks": {"iam_user_accesskey_unused": null,"iam_password_policy_reuse_24": null,"iam_user_console_access_unused": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_6","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Inactive identifiers pose a risk to organizational information because attackers may exploit an inactive identifier to gain undetected access to organizational devices. The owners of the inactive accounts may not notice if unauthorized access to the account has been obtained.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"3_5_7": {"name": "3.5.7 Enforce a minimum password complexity and change of characters when new passwords are created","checks": {"iam_user_accesskey_unused": null,"iam_password_policy_number": null,"iam_password_policy_symbol": null,"iam_password_policy_reuse_24": null,"iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_user_console_access_unused": null,"iam_password_policy_minimum_length_14": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_7","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "This requirement applies to single-factor authentication of individuals using passwords as individual or group authenticators, and in a similar manner, when passwords are used as part of multifactor authenticators. The number of changed characters refers to the number of changes required with respect to the total number of positions in the current password. To mitigate certain brute force attacks against passwords, organizations may also consider salting passwords.","checks_status": {"fail": 0,"pass": 0,"total": 9,"manual": 0}},"3_5_8": {"name": "3.5.8 Prohibit password reuse for a specified number of generations","checks": {"iam_user_accesskey_unused": null,"iam_password_policy_reuse_24": null,"iam_user_console_access_unused": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_5_8","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Password lifetime restrictions do not apply to temporary passwords.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"3_6_1": {"name": "3.6.1 Establish an operational incident-handling capability for organizational systems that includes preparation, detection, analysis, containment, recovery, and user response activities","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_6_1","Section": "3.6 Incident Response","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations recognize that incident handling capability is dependent on the capabilities of organizational systems and the mission/business processes being supported by those systems. Organizations consider incident handling as part of the definition, design, and development of mission/business processes and systems. Incident-related information can be obtained from a variety of sources including audit monitoring, network monitoring, physical access monitoring, user and administrator reports, and reported supply chain events. Effective incident handling capability includes coordination among many organizational entities including mission/business owners, system owners, authorizing officials, human resources offices, physical and personnel security offices, legal departments, operations personnel, procurement offices, and the risk executive. As part of user response activities, incident response training is provided by organizations and is linked directly to the assigned roles and responsibilities of organizational personnel to ensure that the appropriate content and level of detail is included in such training. For example, regular users may only need to know who to call or how to recognize an incident on the system; system administrators may require additional training on how to handle or remediate incidents; and incident responders may receive more specific training on forensics, reporting, system recovery, and restoration. Incident response training includes user training in the identification/reporting of suspicious activities from external and internal sources. User response activities also includes incident response assistance which may consist of help desk support, assistance groups, and access to forensics services or consumer redress services, when required.","checks_status": {"fail": 6,"pass": 4,"total": 14,"manual": 0}},"3_6_2": {"name": "3.6.2 Track, document, and report incidents to designated officials and/or authorities both internal and external to the organization","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_6_2","Section": "3.6 Incident Response","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Tracking and documenting system security incidents includes maintaining records about each incident, the status of the incident, and other pertinent information necessary for forensics, evaluating incident details, trends, and handling. Incident information can be obtained from a variety of sources including incident reports, incident response teams, audit monitoring, network monitoring, physical access monitoring, and user/administrator reports. Reporting incidents addresses specific incident reporting requirements within an organization and the formal incident reporting requirements for the organization. Suspected security incidents may also be reported and include the receipt of suspicious email communications that can potentially contain malicious code. The types of security incidents reported, the content and timeliness of the reports, and the designated reporting authorities reflect applicable laws, Executive Orders, directives, regulations, and policies.","checks_status": {"fail": 6,"pass": 4,"total": 14,"manual": 0}},"3_11_2": {"name": "3.11.2 Scan for vulnerabilities in organizational systems and applications periodically and when new vulnerabilities affecting those systems and applications are identified","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_11_2","Section": "3.11 Risk Assessment","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations determine the required vulnerability scanning for all system components, ensuring that potential sources of vulnerabilities such as networked printers, scanners, and copiers are not overlooked. The vulnerabilities to be scanned are readily updated as new vulnerabilities are discovered, announced, and scanning methods developed. This process ensures that potential vulnerabilities in the system are identified and addressed as quickly as possible. Vulnerability analyses for custom software applications may require additional approaches such as static analysis, dynamic analysis, binary analysis, or a hybrid of the three approaches. Organizations can employ these analysis approaches in source code reviews and in a variety of tools (e.g., static analysis tools, web-based application scanners, binary analyzers) and in source code reviews. Vulnerability scanning includes: scanning for patch levels; scanning for functions, ports, protocols, and services that should not be accessible to users or devices; and scanning for improperly configured or incorrectly operating information flow control mechanisms. To facilitate interoperability, organizations consider using products that are Security Content Automated Protocol (SCAP)-validated, scanning tools that express vulnerabilities in the Common Vulnerabilities and Exposures (CVE) naming convention, and that employ the Open Vulnerability Assessment Language (OVAL) to determine the presence of system vulnerabilities. Sources for vulnerability information include the Common Weakness Enumeration (CWE) listing and the National Vulnerability Database (NVD). Security assessments, such as red team exercises, provide additional sources of potential vulnerabilities for which to scan. Organizations also consider using scanning tools that express vulnerability impact by the Common Vulnerability Scoring System (CVSS). In certain situations, the nature of the vulnerability scanning may be more intrusive or the system component that is the subject of the scanning may contain highly sensitive information. Privileged access authorization to selected system components facilitates thorough vulnerability scanning and protects the sensitive nature of such scanning.","checks_status": {"fail": 1,"pass": 2,"total": 3,"manual": 0}},"3_11_3": {"name": "3.11.3 Remediate vulnerabilities in accordance with risk assessments","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_11_3","Section": "3.11 Risk Assessment","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Vulnerabilities discovered, for example, via the scanning conducted in response to 3.11.2, are remediated with consideration of the related assessment of risk. The consideration of risk influences the prioritization of remediation efforts and the level of effort to be expended in the remediation for specific vulnerabilities.","checks_status": {"fail": 1,"pass": 2,"total": 3,"manual": 0}},"3_12_4": {"name": "3.12.4 Develop, document, and periodically update system security plans that describe system boundaries, system environments of operation, how security requirements are implemented, and the relationships with or connections to other systems","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_12_4","Section": "3.12 Assessment, Authorization, and Monitoring","Service": "aws","SubGroup": null,"SubSection": null}],"description": "System security plans relate security requirements to a set of security controls. System security plans also describe, at a high level, how the security controls meet those security requirements, but do not provide detailed, technical descriptions of the design or implementation of the controls. System security plans contain sufficient information to enable a design and implementation that is unambiguously compliant with the intent of the plans and subsequent determinations of risk if the plan is implemented as intended. Security plans need not be single documents; the plans can be a collection of various documents including documents that already exist. Effective security plans make extensive use of references to policies, procedures, and additional documents (e.g., design and implementation specifications) where more detailed information can be obtained. This reduces the documentation requirements associated with security programs and maintains security-related information in other established management/operational areas related to enterprise architecture, system development life cycle, systems engineering, and acquisition. Federal agencies may consider the submitted system security plans and plans of action as critical inputs to an overall risk management decision to process, store, or transmit CUI on a system hosted by a nonfederal organization and whether it is advisable to pursue an agreement or contract with the nonfederal organization.","checks_status": {"fail": 2,"pass": 3,"total": 9,"manual": 0}},"3_13_1": {"name": "3.13.1 Monitor, control, and protect communications (i.e., information transmitted or received by organizational systems) at the external boundaries and key internal boundaries of organizational systems","checks": {"elb_ssl_listeners": "FAIL","elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","elbv2_waf_acl_attached": "FAIL","rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"cloudtrail_multi_region_enabled": "PASS","acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","cloudtrail_log_file_validation_enabled": "FAIL","cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_1","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Communications can be monitored, controlled, and protected at boundary components and by restricting or prohibiting interfaces in organizational systems. Boundary components include gateways, routers, firewalls, guards, network-based malicious code analysis and virtualization systems, or encrypted tunnels implemented within a system security architecture (e.g., routers protecting firewalls or application gateways residing on protected subnetworks). Restricting or prohibiting interfaces in organizational systems includes restricting external web communications traffic to designated web servers within managed interfaces and prohibiting external traffic that appears to be spoofing internal addresses. Organizations consider the shared nature of commercial telecommunications services in the implementation of security requirements associated with the use of such services. Commercial telecommunications services are commonly based on network components and consolidated management systems shared by all attached commercial customers and may also include third party-provided access lines and other service elements. Such transmission services may represent sources of increased risk despite contract security provisions.","checks_status": {"fail": 10,"pass": 8,"total": 23,"manual": 0}},"3_13_2": {"name": "3.13.2 Employ architectural designs, software development techniques, and systems engineering principles that promote effective information security within organizational systems","checks": {"rds_instance_multi_az": "FAIL","ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","efs_have_backup_enabled": "FAIL","s3_bucket_public_access": null,"elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","dynamodb_tables_pitr_enabled": null,"awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"cloudtrail_multi_region_enabled": "PASS","acm_certificates_expiration_check": "PASS","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"rds_instance_integration_cloudwatch_logs": "FAIL","awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_2","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations apply systems security engineering principles to new development systems or systems undergoing major upgrades. For legacy systems, organizations apply systems security engineering principles to system upgrades and modifications to the extent feasible, given the current state of hardware, software, and firmware components within those systems. The application of systems security engineering concepts and principles helps to develop trustworthy, secure, and resilient systems and system components and reduce the susceptibility of organizations to disruptions, hazards, and threats. Examples of these concepts and principles include developing layered protections; establishing security policies, architecture, and controls as the foundation for design; incorporating security requirements into the system development life cycle; delineating physical and logical security boundaries; ensuring that developers are trained on how to build secure software; and performing threat modeling to identify use cases, threat agents, attack vectors and patterns, design patterns, and compensating controls needed to mitigate risk. Organizations that apply security engineering concepts and principles can facilitate the development of trustworthy, secure systems, system components, and system services; reduce risk to acceptable levels; and make informed risk-management decisions.","checks_status": {"fail": 7,"pass": 8,"total": 23,"manual": 0}},"3_13_3": {"name": "3.13.3 Separate user functionality from system management functionality","checks": {"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_13_3","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "System management functionality includes functions necessary to administer databases, network components, workstations, or servers, and typically requires privileged user access. The separation of user functionality from system management functionality is physical or logical. Organizations can implement separation of system management functionality from user functionality by using different computers, different central processing units, different instances of operating systems, or different network addresses; virtualization techniques; or combinations of these or other methods, as appropriate. This type of separation includes web administrative interfaces that use separate authentication methods for users of any other system resources. Separation of system and user functionality may include isolating administrative interfaces on different domains and with additional access controls.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"3_13_4": {"name": "3.13.4 Prevent unauthorized and unintended information transfer via shared system resources","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_13_4","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The control of information in shared system resources (e.g., registers, cache memory, main memory, hard disks) is also commonly referred to as object reuse and residual information protection. This requirement prevents information produced by the actions of prior users or roles (or the actions of processes acting on behalf of prior users or roles) from being available to any current users or roles (or current processes acting on behalf of current users or roles) that obtain access to shared system resources after those resources have been released back to the system. This requirement also applies to encrypted representations of information. This requirement does not address information remanence, which refers to residual representation of data that has been nominally deleted; covert channels (including storage or timing channels) where shared resources are manipulated to violate information flow restrictions; or components within systems for which there are only single users or roles.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3_13_5": {"name": "3.13.5 Implement subnetworks for publicly accessible system components that are physically or logically separated from internal networks","checks": {"elb_ssl_listeners": "FAIL","ec2_instance_public_ip": "FAIL","elbv2_waf_acl_attached": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"s3_bucket_secure_transport_policy": "FAIL","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_5","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Subnetworks that are physically or logically separated from internal networks are referred to as demilitarized zones (DMZs). DMZs are typically implemented with boundary control devices and techniques that include routers, gateways, firewalls, virtualization, or cloud-based technologies.","checks_status": {"fail": 6,"pass": 6,"total": 20,"manual": 0}},"3_13_6": {"name": "3.13.6 Deny network communications traffic by default and allow network communications traffic by exception (i.e., deny all, permit by exception)","checks": {"ec2_networkacl_allow_ingress_any_port": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_6","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "This requirement applies to inbound and outbound network communications traffic at the system boundary and at identified points within the system. A deny-all, permit-by-exception network communications traffic policy ensures that only those connections which are essential and approved are allowed.","checks_status": {"fail": 1,"pass": 1,"total": 3,"manual": 0}},"3_13_8": {"name": "3.13.8 Implement cryptographic mechanisms to prevent unauthorized disclosure of CUI during transmission unless otherwise protected by alternative physical safeguards","checks": {"elb_ssl_listeners": "FAIL","acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_8","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "This requirement applies to internal and external networks and any system components that can transmit information including servers, notebook computers, desktop computers, mobile devices, printers, copiers, scanners, and facsimile machines. Communication paths outside the physical protection of controlled boundaries are susceptible to both interception and modification. Organizations relying on commercial providers offering transmission services as commodity services rather than as fully dedicated services (i.e., services which can be highly specialized to individual customer needs), may find it difficult to obtain the necessary assurances regarding the implementation of the controls for transmission confidentiality. In such situations, organizations determine what types of confidentiality services are available in commercial telecommunication service packages. If it is infeasible or impractical to obtain the necessary safeguards and assurances of the effectiveness of the safeguards through appropriate contracting vehicles, organizations implement compensating safeguards or explicitly accept the additional risk. An example of an alternative physical safeguard is a protected distribution system (PDS) where the distribution medium is protected against electronic or physical intercept, thereby ensuring the confidentiality of the information being transmitted.","checks_status": {"fail": 2,"pass": 1,"total": 4,"manual": 0}},"3_14_1": {"name": "3.14.1 Identify, report, and correct system flaws in a timely manner","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_14_1","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Organizations identify systems that are affected by announced software and firmware flaws including potential vulnerabilities resulting from those flaws and report this information to designated personnel with information security responsibilities. Security-relevant updates include patches, service packs, hot fixes, and anti-virus signatures. Organizations address flaws discovered during security assessments, continuous monitoring, incident response activities, and system error handling. Organizations can take advantage of available resources such as the Common Weakness Enumeration (CWE) database or Common Vulnerabilities and Exposures (CVE) database in remediating flaws discovered in organizational systems. Organization-defined time periods for updating security-relevant software and firmware may vary based on a variety of factors including the criticality of the update (i.e., severity of the vulnerability related to the discovered flaw). Some types of flaw remediation may require more testing than other types of remediation.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"3_14_2": {"name": "3.14.2 Provide protection from malicious code at designated locations within organizational systems","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_14_2","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Designated locations include system entry and exit points which may include firewalls, remoteaccess servers, workstations, electronic mail servers, web servers, proxy servers, notebook computers, and mobile devices. Malicious code includes viruses, worms, Trojan horses, and spyware. Malicious code can be encoded in various formats (e.g., UUENCODE, Unicode), contained within compressed or hidden files, or hidden in files using techniques such as steganography. Malicious code can be inserted into systems in a variety of ways including web accesses, electronic mail, electronic mail attachments, and portable storage devices. Malicious code insertions occur through the exploitation of system vulnerabilities. Malicious code protection mechanisms include anti-virus signature definitions and reputationbased technologies. A variety of technologies and methods exist to limit or eliminate the effects of malicious code. Pervasive configuration management and comprehensive software integrity controls may be effective in preventing execution of unauthorized code. In addition to commercial off-the-shelf software, malicious code may also be present in custom-built software. This could include logic bombs, back doors, and other types of cyber-attacks that could affect organizational missions/business functions. Traditional malicious code protection mechanisms cannot always detect such code. In these situations, organizations rely instead on other safeguards including secure coding practices, configuration management and control, trusted procurement processes, and monitoring practices to help ensure that software does not perform functions other than the functions intended.","checks_status": {"fail": 2,"pass": 2,"total": 5,"manual": 0}},"3_14_3": {"name": "3.14.3 Monitor system security alerts and advisories and take action in response","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_14_3","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "There are many publicly available sources of system security alerts and advisories. For example, the Department of Homeland Securityās Cybersecurity and Infrastructure Security Agency (CISA) generates security alerts and advisories to maintain situational awareness across the federal government and in nonfederal organizations. Software vendors, subscription services, and industry information sharing and analysis centers (ISACs) may also provide security alerts and advisories. Examples of response actions include notifying relevant external organizations, for example, external mission/business partners, supply chain partners, external service providers, and peer or supporting organizations.","checks_status": {"fail": 1,"pass": 2,"total": 3,"manual": 0}},"3_14_4": {"name": "3.14.4 Update malicious code protection mechanisms when new releases are available","checks": {"guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "3_14_4","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Malicious code protection mechanisms include anti-virus signature definitions and reputationbased technologies. A variety of technologies and methods exist to limit or eliminate the effects of malicious code. Pervasive configuration management and comprehensive software integrity controls may be effective in preventing execution of unauthorized code. In addition to commercial off-the-shelf software, malicious code may also be present in custom-built software. This could include logic bombs, back doors, and other types of cyber-attacks that could affect organizational missions/business functions. Traditional malicious code protection mechanisms cannot always detect such code. In these situations, organizations rely instead on other safeguards including secure coding practices, configuration management and control, trusted procurement processes, and monitoring practices to help ensure that software does not perform functions other than the functions intended.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"3_14_6": {"name": "3.14.6 Monitor organizational systems, including inbound and outbound communications traffic, to detect attacks and indicators of potential attacks","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_14_6","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "System monitoring includes external and internal monitoring. External monitoring includes the observation of events occurring at the system boundary (i.e., part of perimeter defense and boundary protection). Internal monitoring includes the observation of events occurring within the system. Organizations can monitor systems, for example, by observing audit record activities in real time or by observing other system aspects such as access patterns, characteristics of access, and other actions. The monitoring objectives may guide determination of the events. System monitoring capability is achieved through a variety of tools and techniques (e.g., intrusion detection systems, intrusion prevention systems, malicious code protection software, scanning tools, audit record monitoring software, network monitoring software). Strategic locations for monitoring devices include selected perimeter locations and near server farms supporting critical applications, with such devices being employed at managed system interfaces. The granularity of monitoring information collected is based on organizational monitoring objectives and the capability of systems to support such objectives. System monitoring is an integral part of continuous monitoring and incident response programs. Output from system monitoring serves as input to continuous monitoring and incident response programs. A network connection is any connection with a device that communicates through a network (e.g., local area network, Internet). A remote connection is any connection with a device communicating through an external network (e.g., the Internet). Local, network, and remote connections can be either wired or wireless. Unusual or unauthorized activities or conditions related to inbound/outbound communications traffic include internal traffic that indicates the presence of malicious code in systems or propagating among system components, the unauthorized exporting of information, or signaling to external systems. Evidence of malicious code is used to identify potentially compromised systems or system components. System monitoring requirements, including the need for specific types of system monitoring, may be referenced in other requirements.","checks_status": {"fail": 5,"pass": 4,"total": 12,"manual": 0}},"3_14_7": {"name": "3.14.7 Identify unauthorized use of organizational systems","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_14_7","Section": "3.14 System and Information integrity","Service": "aws","SubGroup": null,"SubSection": null}],"description": "System monitoring includes external and internal monitoring. System monitoring can detect unauthorized use of organizational systems. System monitoring is an integral part of continuous monitoring and incident response programs. Monitoring is achieved through a variety of tools and techniques (e.g., intrusion detection systems, intrusion prevention systems, malicious code protection software, scanning tools, audit record monitoring software, network monitoring software). Output from system monitoring serves as input to continuous monitoring and incident response programs. Unusual/unauthorized activities or conditions related to inbound and outbound communications traffic include internal traffic that indicates the presence of malicious code in systems or propagating among system components, the unauthorized exporting of information, or signaling to external systems. Evidence of malicious code is used to identify potentially compromised systems or system components. System monitoring requirements, including the need for specific types of system monitoring, may be referenced in other requirements.","checks_status": {"fail": 5,"pass": 4,"total": 12,"manual": 0}},"3_1_12": {"name": "3.1.12 Monitor and control remote access sessions","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_12","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Remote access is access to organizational systems by users (or processes acting on behalf of users) communicating through external networks (e.g., the Internet). Remote access methods include dial-up, broadband, and wireless. Organizations often employ encrypted virtual private networks (VPNs) to enhance confidentiality over remote connections. The use of encrypted VPNs does not make the access non-remote; however, the use of VPNs, when adequately provisioned with appropriate control (e.g., employing encryption techniques for confidentiality protection), may provide sufficient assurance to the organization that it can effectively treat such connections as internal networks. VPNs with encrypted tunnels can affect the capability to adequately monitor network communications traffic for malicious code. Automated monitoring and control of remote access sessions allows organizations to detect cyberattacks and help to ensure ongoing compliance with remote access policies by auditing connection activities of remote users on a variety of system components (e.g., servers, workstations, notebook computers, smart phones, and tablets).","checks_status": {"fail": 4,"pass": 4,"total": 11,"manual": 0}},"3_1_13": {"name": "3.1.13 Employ cryptographic mechanisms to protect the confidentiality of remote access sessions","checks": {"elb_ssl_listeners": "FAIL","s3_bucket_secure_transport_policy": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_13","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Cryptographic standards include FIPS-validated cryptography and NSA-approved cryptography.","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"3_1_14": {"name": "3.1.14 Route remote access via managed access control points","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"iam_user_mfa_enabled_console_access": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_14","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Routing remote access through managed access control points enhances explicit, organizational control over such connections, reducing the susceptibility to unauthorized access to organizational systems resulting in the unauthorized disclosure of CUI.","checks_status": {"fail": 3,"pass": 5,"total": 14,"manual": 0}},"3_1_20": {"name": "3.1.20 Verify and control/limit connections to and use of external systems","checks": {"ec2_networkacl_allow_ingress_any_port": "FAIL","s3_account_level_public_access_blocks": null,"ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_1_20","Section": "3.1 Access Control","Service": "aws","SubGroup": null,"SubSection": null}],"description": "External systems are systems or components of systems for which organizations typically have no direct supervision and authority over the application of security requirements and controls or the determination of the effectiveness of implemented controls on those systems. External systems include personally owned systems, components, or devices and privately-owned computing and communications devices resident in commercial or public facilities. This requirement also addresses the use of external systems for the processing, storage, or transmission of CUI, including accessing cloud services (e.g., infrastructure as a service, platform as a service, or software as a service) from organizational systems. Organizations establish terms and conditions for the use of external systems in accordance with organizational security policies and procedures. Terms and conditions address as a minimum, the types of applications that can be accessed on organizational systems from external systems. If terms and conditions with the owners of external systems cannot be established, organizations may impose restrictions on organizational personnel using those external systems. This requirement recognizes that there are circumstances where individuals using external systems (e.g., contractors, coalition partners) need to access organizational systems. In those situations, organizations need confidence that the external systems contain the necessary controls so as not to compromise, damage, or otherwise harm organizational systems. Verification that the required controls have been effectively implemented can be achieved by third-party, independent assessments, attestations, or other means, depending on the assurance or confidence level required by organizations. Note that while āexternalā typically refers to outside of the organization's direct supervision and authority, that is not always the case. Regarding the protection of CUI across an organization, the organization may have systems that process CUI and others that do not. And among the systems that process CUI there are likely access restrictions for CUI that apply between systems. Therefore, from the perspective of a given system, other systems within the organization may be considered 'external' to that system.","checks_status": {"fail": 2,"pass": 1,"total": 5,"manual": 0}},"3_5_10": {"name": "3.5.10 Store and transmit only cryptographically-protected passwords","checks": {"ec2_ebs_volume_encryption": "PASS","elbv2_insecure_ssl_ciphers": "PASS","s3_bucket_default_encryption": "PASS","s3_bucket_secure_transport_policy": "FAIL","apigateway_restapi_client_certificate_enabled": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_5_10","Section": "3.5 Identification and Authentication","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Cryptographically-protected passwords use salted one-way cryptographic hashes of passwords.","checks_status": {"fail": 2,"pass": 3,"total": 6,"manual": 0}},"3_13_11": {"name": "3.13.11 Employ FIPS-validated cryptography when used to protect the confidentiality of CUI","checks": {"ec2_ebs_volume_encryption": "PASS","s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","acm_certificates_expiration_check": "PASS","cloudtrail_kms_encryption_enabled": "FAIL","s3_bucket_secure_transport_policy": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","dynamodb_tables_kms_cmk_encryption_enabled": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_11","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Cryptography can be employed to support many security solutions including the protection of controlled unclassified information, the provision of digital signatures, and the enforcement of information separation when authorized individuals have the necessary clearances for such information but lack the necessary formal access approvals. Cryptography can also be used to support random number generation and hash generation. Cryptographic standards include FIPSvalidated cryptography and/or NSA-approved cryptography.","checks_status": {"fail": 6,"pass": 3,"total": 12,"manual": 0}},"3_13_15": {"name": "3.13.15 Protect the authenticity of communications sessions","checks": {"elb_ssl_listeners": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_15","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Authenticity protection includes protecting against man-in-the-middle attacks, session hijacking, and the insertion of false information into communications sessions. This requirement addresses communications protection at the session versus packet level (e.g., sessions in service-oriented architectures providing web-based services) and establishes grounds for confidence at both ends of communications sessions in ongoing identities of other parties and in the validity of information transmitted.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3_13_16": {"name": "3.13.16 Protect the confidentiality of CUI at rest","checks": {"ec2_ebs_volume_encryption": "PASS","s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","s3_bucket_secure_transport_policy": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","dynamodb_tables_kms_cmk_encryption_enabled": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "3_13_16","Section": "3.13 System and Communications Protection","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Information at rest refers to the state of information when it is not in process or in transit and is located on storage devices as specific components of systems. The focus of protection at rest is not on the type of storage device or the frequency of access but rather the state of the information. Organizations can use different mechanisms to achieve confidentiality protections, including the use of cryptographic mechanisms and file share scanning. Organizations may also use other controls including secure off-line storage in lieu of online storage when adequate protection of information at rest cannot otherwise be achieved or continuous monitoring to identify malicious code at rest.","checks_status": {"fail": 6,"pass": 2,"total": 12,"manual": 0}}},"requirements_passed": 14,"requirements_failed": 35,"requirements_manual": 1,"total_requirements": 50,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "168b9e98-d0d8-47a8-b53a-32097ec095ac","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "nist_800_53_revision_4_aws","framework": "NIST-800-53-Revision-4","version": "","description": "NIST 800-53 is a regulatory standard that defines the minimum baseline of security controls for all U.S. federal information systems except those related to national security. The controls defined in this standard are customizable and address a diverse set of security and privacy requirements.","region": "eu-west-1","requirements": {"ac_2": {"name": "Account Management (AC-2)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","iam_root_mfa_enabled": null,"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_password_policy_reuse_24": null,"iam_rotate_access_key_90_days": null,"iam_user_console_access_unused": null,"redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_2","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Manage system accounts, group memberships, privileges, workflow, notifications, deactivations, and authorizations.","checks_status": {"fail": 3,"pass": 3,"total": 18,"manual": 0}},"ac_3": {"name": "Access Enforcement (AC-3)","checks": {"iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"iam_user_accesskey_unused": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"iam_user_console_access_unused": null,"redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_3","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system enforces approved authorizations for logical access to information and system resources in accordance with applicable access control policies.","checks_status": {"fail": 0,"pass": 3,"total": 14,"manual": 0}},"ac_4": {"name": "Information Flow Enforcement (AC-4)","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"acm_certificates_expiration_check": "PASS","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_4","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system enforces approved authorizations for controlling the flow of information within the system and between interconnected systems based on organization-defined information flow control policies.","checks_status": {"fail": 3,"pass": 7,"total": 17,"manual": 0}},"ac_5": {"name": "Separation Of Duties (AC-5)","checks": {"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_5","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Separate duties of individuals to prevent malevolent activity. automate separation of duties and access authorizations.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"ac_6": {"name": "Least Privilege (AC-6)","checks": {"ec2_instance_public_ip": "FAIL","iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"iam_user_accesskey_unused": null,"ec2_instance_imdsv2_enabled": "PASS","rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","iam_user_console_access_unused": null,"redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","iam_policy_attached_only_to_group_or_roles": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_6","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization employs the principle of least privilege, allowing only authorized accesses for users (or processes acting on behalf of users) which are necessary to accomplish assigned tasks in accordance with organizational missions and business functions.","checks_status": {"fail": 1,"pass": 5,"total": 18,"manual": 0}},"au_2": {"name": "Event Logging (AU-2)","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_2","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Automate security audit function with other organizational entities. Enable mutual support of audit of auditable events.","checks_status": {"fail": 6,"pass": 2,"total": 12,"manual": 0}},"au_3": {"name": "Content of Audit Records (AU-3)","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_3","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system generates audit records containing information that establishes what type of event occurred, when the event occurred, where the event occurred, the source of the event, the outcome of the event, and the identity of any individuals or subjects associated with the event.","checks_status": {"fail": 6,"pass": 2,"total": 12,"manual": 0}},"au_9": {"name": "Protection of Audit Information (AU-9)","checks": {"cloudtrail_kms_encryption_enabled": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_9","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects audit information and audit tools from unauthorized access, modification, and deletion.","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"ca_7": {"name": "Continuous Monitoring (CA-7)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ca_7","Section": "Security Assessment And Authorization (CA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Continuously monitor configuration management processes. Determine security impact, environment and operational risks.","checks_status": {"fail": 2,"pass": 3,"total": 9,"manual": 0}},"cm_2": {"name": "Baseline Configuration (CM-2)","checks": {"elbv2_deletion_protection": "FAIL","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","cloudtrail_multi_region_enabled": "PASS","ec2_instance_older_than_specific_days": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_2","Section": "Configuration Management (CM)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization develops, documents, and maintains under configuration control, a current baseline configuration of the information system.","checks_status": {"fail": 5,"pass": 1,"total": 6,"manual": 0}},"cm_7": {"name": "Least Functionality (CM-7)","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_7","Section": "Configuration Management (CM)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization configures the information system to provide only essential capabilities and prohibits or restricts the use of the functions, ports, protocols, and/or services.","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"cp_9": {"name": "Information System Backup (CP-9)","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","dynamodb_tables_pitr_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cp_9","Section": "Contingency Planning (CP)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization conducts backups of user-level information, system-level information and information system documentation including security-related documentation contained in the information system and protects the confidentiality, integrity, and availability of backup information at storage locations.","checks_status": {"fail": 1,"pass": 1,"total": 4,"manual": 0}},"ia_2": {"name": "Identification and Authentication (Organizational users) (IA-2)","checks": {"iam_password_policy_reuse_24": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_2","Section": "Identification and Authentication (IA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system uniquely identifies and authenticates organizational users (or processes acting on behalf of organizational users).","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"ra_5": {"name": "Vulnerability Scanning (RA-5)","checks": {"guardduty_is_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ra_5","Section": "Risk Assessment (RA)","Service": "guardduty","SubGroup": null,"SubSection": null}],"description": "Scan for system vulnerabilities. Share vulnerability information and security controls that eliminate vulnerabilities.","checks_status": {"fail": 1,"pass": 1,"total": 2,"manual": 0}},"sa_3": {"name": "System Development Life Cycle (SA-3)","checks": {"ec2_instance_managed_by_ssm": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sa_3","Section": "System and Services Acquisition (SA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization manages the information system using organization-defined system development life cycle, defines and documents information security roles and responsibilities throughout the system development life cycle, identifies individuals having information security roles and responsibilities and integrates the organizational information security risk management process into system development life cycle activities.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"sc_2": {"name": "Application Partitioning (SC-2)","checks": {"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc_2","Section": "System and Communications Protection (SC)","Service": "iam","SubGroup": null,"SubSection": null}],"description": "The information system separates user functionality (including user interface services) from information system management functionality.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"sc_4": {"name": "Information In Shared Resources (SC-4)","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc_4","Section": "System and Communications Protection (SC)","Service": "ebs","SubGroup": null,"SubSection": null}],"description": "The information system prevents unauthorized and unintended information transfer via shared system resources.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"sc_5": {"name": "Denial Of Service Protection (SC-5)","checks": {"rds_instance_multi_az": "FAIL","rds_instance_deletion_protection": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_5","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects against or limits the effects of the following types of denial of service attacks: [Assignment: organization-defined types of denial of service attacks or references to sources for such information] by employing [Assignment: organization-defined security safeguards].","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"sc_7": {"name": "Boundary Protection (SC-7)","checks": {"elb_ssl_listeners": "FAIL","ec2_instance_public_ip": "FAIL","elbv2_waf_acl_attached": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"s3_bucket_secure_transport_policy": "FAIL","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_7","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system: a. Monitors and controls communications at the external boundary of the system and at key internal boundaries within the system; b. Implements subnetworks for publicly accessible system components that are [Selection: physically; logically] separated from internal organizational networks; and c. Connects to external networks or information systems only through managed interfaces consisting of boundary protection devices arranged in accordance with an organizational security architecture.","checks_status": {"fail": 6,"pass": 6,"total": 20,"manual": 0}},"sc_8": {"name": "Transmission Confidentiality And Integrity (SC-8)","checks": {"elb_ssl_listeners": "FAIL","s3_bucket_secure_transport_policy": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_8","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects the [Selection (one or more): confidentiality; integrity] of transmitted information.","checks_status": {"fail": 2,"pass": 0,"total": 3,"manual": 0}},"si_4": {"name": "Information System Monitoring (SI-4)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_waf_acl_attached": "FAIL","ec2_instance_imdsv2_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_4","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization: a.Monitors the information system to detect: 1. Attacks and indicators of potential attacks in accordance with [Assignment: organization-defined monitoring objectives]; and 2.Unauthorized local, network, and remote connections; b. Identifies unauthorized use of the information system through [Assignment: organization-defined techniques and methods]; c. Deploys monitoring devices: 1. Strategically within the information system to collect organization-determined essential information; and 2. At ad hoc locations within the system to track specific types of transactions of interest to the organization; d. Protects information obtained from intrusion-monitoring tools from unauthorized access, modification, and deletion; e. Heightens the level of information system monitoring activity whenever there is an indication of increased risk to organizational operations and assets, individuals, other organizations, or the Nation based on law enforcement information, intelligence information, or other credible sources of information; f. Obtains legal opinion with regard to information system monitoring activities in accordance with applicable federal laws, Executive Orders, directives, policies, or regulations; and g. Provides [Assignment: organization-defined information system monitoring information] to [Assignment: organization-defined personnel or roles] [Selection (one or more): as needed; [Assignment: organization-defined frequency]].","checks_status": {"fail": 3,"pass": 3,"total": 10,"manual": 0}},"si_7": {"name": "Software, Firmware, and Information Integrity (SI-7)","checks": {"cloudtrail_log_file_validation_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_7","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization employs integrity verification tools to detect unauthorized changes to [Assignment: organization-defined software, firmware, and information].","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"ac_21": {"name": "Information Sharing (AC-21)","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","emr_cluster_master_nodes_no_public_ip": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_21","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Facilitate information sharing. Enable authorized users to grant access to partners.","checks_status": {"fail": 1,"pass": 4,"total": 11,"manual": 0}},"au_11": {"name": "Audit Record Retention (AU-11)","checks": {"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_11","Section": "Audit and Accountability (AU)","Service": "cloudwatch","SubGroup": null,"SubSection": null}],"description": "The organization retains audit records for [Assignment: organization-defined time period consistent with records retention policy] to provide support for after-the-fact investigations of security incidents and to meet regulatory and organizational information retention requirements.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"au_12": {"name": "Audit Generation (AU-12)","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_12","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Audit events defined in AU-2. Allow trusted personnel to select which events to audit. Generate audit records for events.","checks_status": {"fail": 6,"pass": 2,"total": 12,"manual": 0}},"cp_10": {"name": "Information System Recovery And Reconstitution (CP-10)","checks": {"rds_instance_multi_az": "FAIL","efs_have_backup_enabled": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cp_10","Section": "Contingency Planning (CP)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization provides for the recovery and reconstitution of the information system to a known state after a disruption, compromise, or failure.","checks_status": {"fail": 4,"pass": 1,"total": 7,"manual": 0}},"sa_10": {"name": "Developer Configuration Management (SA-10)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_managed_by_ssm": "FAIL","guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sa_10","Section": "System and Services Acquisition (SA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization requires the developer of the information system, system component, or information system service to: a. Perform configuration management during system, component, or service [Selection (one or more): design; development; implementation; operation]; b. Document, manage, and control the integrity of changes to [Assignment: organization-defined configuration items under configuration management]; c. Implement only organization-approved changes to the system, component, or service; d. Document approved changes to the system, component, or service and the potential security impacts of such changes; and e. Track security flaws and flaw resolution within the system, component, or service and report findings to [Assignment: organization-defined personnel].","checks_status": {"fail": 2,"pass": 2,"total": 4,"manual": 0}},"sc_12": {"name": "Cryptographic Key Establishment And Management (SC-12)","checks": {"kms_cmk_rotation_enabled": null,"acm_certificates_expiration_check": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc_12","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization establishes and manages cryptographic keys for required cryptography employed within the information system in accordance with [Assignment: organization-defined requirements for key generation, distribution, storage, access, and destruction].","checks_status": {"fail": 0,"pass": 1,"total": 2,"manual": 0}},"sc_13": {"name": "Cryptographic Protection (SC-13)","checks": {"dynamodb_tables_kms_cmk_encryption_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc_13","Section": "System and Communications Protection (SC)","Service": "dynamodb","SubGroup": null,"SubSection": null}],"description": "The information system implements [Assignment: organization-defined cryptographic uses and type of cryptography required for each use] in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"sc_23": {"name": "Session Authenticity (SC-23)","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc_23","Section": "System and Communications Protection (SC)","Service": "elb","SubGroup": null,"SubSection": null}],"description": "The information system protects the authenticity of communications sessions.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"sc_28": {"name": "Protection Of Information At Rest (SC-28)","checks": {"ec2_ebs_volume_encryption": "PASS","ec2_ebs_default_encryption": "PASS","s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_kms_encryption_enabled": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_28","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects the [Selection (one or more): confidentiality; integrity] of [Assignment: organization-defined information at rest].","checks_status": {"fail": 5,"pass": 3,"total": 12,"manual": 0}},"si_12": {"name": "Information Handling and Retention (SI-12)","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_12","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization handles and retains information within the information system and information output from the system in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and operational requirements.","checks_status": {"fail": 3,"pass": 1,"total": 6,"manual": 0}},"ac_2_1": {"name": "AC-2(1) Automated System Account Management","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","iam_user_accesskey_unused": null,"iam_password_policy_reuse_24": null,"iam_rotate_access_key_90_days": null,"iam_user_console_access_unused": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_2_1","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": "Account Management (AC-2)"}],"description": "Access control policies (e.g., identity or role-based policies, control matrices, and cryptography) control access between active entities or subjects (i.e., users or processes acting on behalf of users) and passive entities or objects (e.g., devices, files, records, and domains) in systems. Access enforcement mechanisms can be employed at the application and service level to provide increased information security. Other systems include systems internal and external to the organization. This requirement focuses on account management for systems and applications. The definition of and enforcement of access authorizations, other than those determined by account type (e.g., privileged verses non-privileged) are addressed in requirement 3.1.2.","checks_status": {"fail": 0,"pass": 2,"total": 6,"manual": 0}},"ac_2_3": {"name": "AC-2(3) Disable Inactive Accounts","checks": {"iam_user_accesskey_unused": null,"iam_user_console_access_unused": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_2_3","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": "Account Management (AC-2)"}],"description": "The information system automatically disables inactive accounts after 90 days for user accounts.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"ac_2_4": {"name": "AC-2(4) Automated Audit Actions","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_2_4","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": "Account Management (AC-2)"}],"description": "The information system automatically audits account creation, modification, enabling, disabling, and removal actions, and notifies [Assignment: organization-defined personnel or roles].","checks_status": {"fail": 2,"pass": 3,"total": 11,"manual": 0}},"au_6_1": {"name": "AU-6(1) Process Integration","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_6_1","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": "Audit Review, Analysis And Reporting (AU-6)"}],"description": "The organization employs automated mechanisms to integrate audit review, analysis,and reporting processes to support organizational processes for investigation and response to suspicious activities.","checks_status": {"fail": 1,"pass": 2,"total": 7,"manual": 0}},"au_6_3": {"name": "AU-6(3) Correlate Audit Repositories","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_6_3","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": "Audit Review, Analysis And Reporting (AU-6)"}],"description": "The organization analyzes and correlates audit records across different repositories to gain organization-wide situational awareness.","checks_status": {"fail": 1,"pass": 2,"total": 7,"manual": 0}},"au_7_1": {"name": "AU-7(1) Automatic Processing","checks": {"cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au_7_1","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system provides the capability to process audit records for events of interest based on [Assignment: organization-defined audit fields within audit records].","checks_status": {"fail": 1,"pass": 0,"total": 5,"manual": 0}},"au_9_2": {"name": "AU-9(2) Audit Backup On Separate Physical Systems / Components","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "au_9_2","Section": "Audit and Accountability (AU)","Service": "s3","SubGroup": null,"SubSection": "Protection of Audit Information (AU-9)"}],"description": "The information system backs up audit records [Assignment: organization-defined frequency] onto a physically different system or system component than the system or component being audited.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"cm_8_1": {"name": "CM-8(1) Updates During Installation / Removals","checks": {"ec2_instance_managed_by_ssm": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_8_1","Section": "Configuration Management (CM)","Service": "ec2","SubGroup": null,"SubSection": "Information System Component Inventory (CM-8)"}],"description": "The organization develops and documents an inventory of information system components that accurately reflects the current information system, includes all components within the authorization boundary of the information system, is at the level of granularity deemed necessary for tracking and reporting and reviews and updates the information system component inventory.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"cm_8_3": {"name": "CM-8(3) Automated Unauthorized Component Detection","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_8_3","Section": "Configuration Management (CM)","Service": "aws","SubGroup": null,"SubSection": "Information System Component Inventory (CM-8)"}],"description": "The organization employs automated mechanisms to detect the presence of unauthorized hardware, software, and firmware components within the information system and takes actions (disables network access by such components, isolates the components etc) when unauthorized components are detected.","checks_status": {"fail": 2,"pass": 0,"total": 3,"manual": 0}},"ia_2_1": {"name": "IA-2(1) Network Access To Privileged Accounts","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_2_1","Section": "Identification and Authentication (IA)","Service": "iam","SubGroup": null,"SubSection": "Identification and Authentication (Organizational users) (IA-2)"}],"description": "The information system implements multi-factor authentication for network access to privileged accounts.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"ia_2_2": {"name": "IA-2(2) Network Access To Non-Privileged Accounts","checks": {"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_2_2","Section": "Identification and Authentication (IA)","Service": "iam","SubGroup": null,"SubSection": "Identification and Authentication (Organizational users) (IA-2)"}],"description": "The information system implements multifactor authentication for network access to non-privileged accounts.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"ia_5_1": {"name": "IA-5(1) Password-Based Authentication","checks": {"iam_password_policy_reuse_24": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_5_1","Section": "Identification and Authentication (IA)","Service": "iam","SubGroup": null,"SubSection": "Authenticator Management (IA-5)"}],"description": "The information system, for password-based authentication that enforces minimum password complexity, stores and transmits only cryptographically-protected passwords, enforces password minimum and maximum lifetime restrictions, prohibits password reuse, allows the use of a temporary password for system logons with an immediate change to a permanent password etc.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"ia_5_4": {"name": "IA-5(4) Automated Support For Password Strength Determination","checks": {"iam_password_policy_reuse_24": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_5_4","Section": "Identification and Authentication (IA)","Service": "iam","SubGroup": null,"SubSection": "Authenticator Management (IA-5)"}],"description": "The organization employs automated tools to determine if password authenticators are sufficiently strong to satisfy [Assignment: organization-defined requirements].","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"ia_5_7": {"name": "IA-5(7) No Embedded Unencrypted Static Authenticators","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_5_7","Section": "Identification and Authentication (IA)","Service": "codebuild","SubGroup": null,"SubSection": "Authenticator Management (IA-5)"}],"description": "The organization ensures that unencrypted static authenticators are not embedded in applications or access scripts or stored on function keys.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ir_4_1": {"name": "IR-4(1) Automated Incident Handling Processes","checks": {"guardduty_no_high_severity_findings": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ir_4_1","Section": "Incident Response (IR)","Service": "aws","SubGroup": null,"SubSection": "Incident Handling (IR-4)"}],"description": "The organization employs automated mechanisms to support the incident handling process.","checks_status": {"fail": 1,"pass": 0,"total": 5,"manual": 0}},"ir_6_1": {"name": "IR-6(1) Automated Reporting","checks": {"guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ir_6_1","Section": "Incident Response (IR)","Service": "guardduty","SubGroup": null,"SubSection": "Incident Reporting (IR-6)"}],"description": "The organization employs automated mechanisms to assist in the reporting of security incidents.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"ir_7_1": {"name": "IR-7(1) Automation Support For Availability Of Information / Support","checks": {"guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ir_7_1","Section": "Incident Response (IR)","Service": "guardduty","SubGroup": null,"SubSection": "Incident Response Assistance (IR-7)"}],"description": "The organization employs automated mechanisms to increase the availability of incident response-related information and support.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"sc_7_3": {"name": "SC-7(3) Access Points","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_7_3","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": "Boundary Protection (SC-7)"}],"description": "The organization limits the number of external network connections to the information system.","checks_status": {"fail": 3,"pass": 6,"total": 16,"manual": 0}},"sc_8_1": {"name": "SC-8(1) Cryptographic Or Alternate Physical Protection","checks": {"elb_ssl_listeners": "FAIL","s3_bucket_secure_transport_policy": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_8_1","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": "Transmission Confidentiality And Integrity (SC-8)"}],"description": "The information system implements cryptographic mechanisms to [Selection (one or more): prevent unauthorized disclosure of information; detect changes to information] during transmission unless otherwise protected by [Assignment: organization-defined alternative physical safeguards].","checks_status": {"fail": 2,"pass": 0,"total": 3,"manual": 0}},"si_2_2": {"name": "SI-2(2) Automates Flaw Remediation Status","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_2_2","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Flaw Remediation (SI-2)"}],"description": "The organization employs automated mechanisms to determine the state of information system components with regard to flaw remediation.","checks_status": {"fail": 2,"pass": 0,"total": 3,"manual": 0}},"si_4_1": {"name": "SI-4(1) System-Wide Intrusion Detection System","checks": {"guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "si_4_1","Section": "System and Information Integrity (SI)","Service": "guardduty","SubGroup": null,"SubSection": "Information System Monitoring (SI-4)"}],"description": "The organization connects and configures individual intrusion detection tools into an information system-wide intrusion detection system.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"si_4_2": {"name": "SI-4(2) Automated Tools For Real-Time Analysis","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_4_2","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Information System Monitoring (SI-4)"}],"description": "The organization employs automated tools to support near real-time analysis of events.","checks_status": {"fail": 1,"pass": 3,"total": 8,"manual": 0}},"si_4_4": {"name": "SI-4(4) Inbound and Outbound Communications Traffic","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_4_4","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Information System Monitoring (SI-4)"}],"description": "The information system monitors inbound and outbound communications traffic continuously for unusual or unauthorized activities or conditions.","checks_status": {"fail": 1,"pass": 2,"total": 7,"manual": 0}},"si_4_5": {"name": "SI-4(5) System-Generated Alerts","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_4_5","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Information System Monitoring (SI-4)"}],"description": "The information system alerts organization-defined personnel or roles when the following indications of compromise or potential compromise occur: [Assignment: organization-defined compromise indicators].","checks_status": {"fail": 1,"pass": 2,"total": 7,"manual": 0}},"si_7_1": {"name": "SI-7(1) Integrity Checks","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","cloudtrail_log_file_validation_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "si_7_1","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Software, Firmware, and Information Integrity (SI-7)"}],"description": "The information system performs an integrity check of security relevant events at least monthly.","checks_status": {"fail": 3,"pass": 0,"total": 3,"manual": 0}},"ac_17_1": {"name": "AC-17(1) Automated Monitoring/Control","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_17_1","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system monitors and controls remote access methods.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ac_17_2": {"name": "AC-17(2) Protection Of Confidentiality/Integrity Using Encryption","checks": {"elb_ssl_listeners": "FAIL","acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_17_2","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system implements cryptographic mechanisms to protect the confidentiality and integrity of remote access sessions.","checks_status": {"fail": 2,"pass": 1,"total": 3,"manual": 0}},"ac_17_3": {"name": "AC-17(3) Managed Access Control Points","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_17_3","Section": "Access Control (AC)","Service": "vpc","SubGroup": null,"SubSection": null}],"description": "The information system routes all remote accesses through organization-defined managed network access control points.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ac_2_12": {"name": "AC-2(12) Account Monitoring","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_2_12","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": "Account Management (AC-2)"}],"description": "Monitors and reports atypical usage of information system accounts to organization-defined personnel or roles.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ac_6_10": {"name": "AC-6(10) Prohibit Non-Privileged Users From Executing Privileged Functions","checks": {"iam_no_root_access_key": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_6_10","Section": "Access Control (AC)","Service": "iam","SubGroup": null,"SubSection": "Least Privilege (AC-6)"}],"description": "The information system prevents non-privileged users from executing privileged functions to include disabling, circumventing, or altering implemented security safeguards/countermeasures.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"ia_2_11": {"name": "IA-2(11) Remote Access - Separate Device","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia_2_11","Section": "Identification and Authentication (IA)","Service": "iam","SubGroup": null,"SubSection": "Identification and Authentication (Organizational users) (IA-2)"}],"description": "The information system implements multifactor authentication for remote access to privileged and non-privileged accounts such that one of the factors is provided by a device separate from the system gaining access and the device meets [Assignment: organization-defined strength of mechanism requirements].","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"si_4_16": {"name": "SI-4(16) Correlate Monitoring Information","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "si_4_16","Section": "System and Information Integrity (SI)","Service": "aws","SubGroup": null,"SubSection": "Information System Monitoring (SI-4)"}],"description": "The organization correlates information from monitoring tools employed throughout the information system.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}}},"requirements_passed": 18,"requirements_failed": 41,"requirements_manual": 5,"total_requirements": 64,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "1c8c75df-34ec-48f2-b6e2-5dba27d9b734","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "kisa_isms_p_2023_aws","framework": "KISA-ISMS-P","version": "2023","description": "The ISMS-P certification, established by KISA (Korea Internet & Security Agency), is a system where an independent certification body evaluates whether a company or organization's information security and privacy protection measures comply with certification standards, and grants certification. This helps organizations improve public trust in their services and respond effectively to increasingly complex cyber threats. The ISMS-P framework also provides comprehensive guidelines for systematically establishing, implementing, and managing information security and privacy protection.","region": "eu-west-1","requirements": {"1.1.1": {"name": "Executive Participation","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.1 Executive Participation","Subdomain": "1.1. Management System","AuditEvidence": ["Information protection and personal information protection reporting system (e.g., communication plan)","Minutes of the Information Protection and Personal Information Protection Committee","Information protection and personal information protection policies/guidelines (including executive approval records)","Information protection plans and internal management plans (including executive approval records)","Information protection and personal information protection organization chart"],"AuditChecklist": ["Is there documentation outlining the responsibilities and roles of executives to ensure their participation in the establishment and operation of the information protection and personal information protection management system?","Is there a reporting, review, and approval process in place to ensure that executives actively participate in decision-making regarding information protection and personal information protection activities?"],"NonComplianceCases": ["Case 1: Although it is stated in the information protection and personal information protection policy to report the status of information protection and personal information protection to the executives on a quarterly basis, no such reports have been made for an extended period.","Case 2: In performing major information protection activities (e.g., risk assessment, determining risk acceptance levels, reviewing information protection measures and implementation plans, reviewing the results of information protection measures, security audits, etc.), executives or those authorized by the executives did not participate in decision-making or there was no evidence of their involvement."],"RelatedRegulations": []}],"description": "The CEO must establish and operate a reporting and decision-making system to ensure executive participation in the establishment and operation of the information protection and personal information protection management system.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.1.2": {"name": "Designation of Chief Officers","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.2 Designation of Chief Officers","Subdomain": "1.1. Management System","AuditEvidence": ["Documents related to the appointment of the CISO and CPO (e.g., personnel orders, personnel records)","Information protection and personal information protection organization chart","Information protection and personal information protection policies/guidelines","Job descriptions (roles and responsibilities of the CISO and CPO)","Records of CISO reports","Internal management plans (regarding the appointment of the CPO)"],"AuditChecklist": ["Has the CEO officially designated a chief officer responsible for overseeing information protection and personal information protection?","Are the CISO and CPO appointed at an executive level with authority to allocate resources such as budget and personnel, and do they meet the qualifications required by relevant laws?"],"NonComplianceCases": ["Case 1: Failure to appoint and report a CISO as required under the Information and Communications Network Act, even though the organization is obligated to do so.","Case 2: Appointing a person without substantial authority and status as the CPO, making it difficult to believe that they are responsible for overseeing personal information processing.","Case 3: Although the organization chart specifies the CISO and CPO, the formal appointment process, such as issuing personnel orders, was not followed.","Case 4: Although the entity is subject to ISMS certification and had over 5 trillion won in assets at the end of the previous year, the CISO also holds the position of CIO, in violation of the ISMS requirements."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures), Article 31 (Designation of a Personal Information Protection Officer)","Information and Communications Network Act, Article 45-3 (Designation of a Chief Information Security Officer, etc.)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The CEO must appoint a Chief Information Security Officer (CISO) responsible for information protection and a Chief Privacy Officer (CPO) responsible for personal information protection, both at an executive level with authority to allocate resources such as budget and personnel.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.1.3": {"name": "Organization Structure","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.3 Organization Structure","Subdomain": "1.1. Management System","AuditEvidence": ["Information protection and personal information protection committee regulations/minutes","Information protection and personal information protection working group regulations/minutes","Information protection and personal information protection organization chart","Internal management plan","Job descriptions"],"AuditChecklist": ["Has the organization established and operated a working group with expertise to support the work of the CISO and CPO and systematically implement the organization's information protection and personal information protection activities?","Has the organization established and operated a committee that can review, approve, and make decisions on important information protection and personal information protection matters across the organization?","Has the organization established and operated a working group composed of information protection and personal information protection officers and department-level personnel for enterprise-wide information protection and personal information protection activities?"],"NonComplianceCases": ["Case 1: The Information Protection and Personal Information Protection Committee was established, but it consists only of department heads without the inclusion of executives, making it difficult to make decisions on the organization's key information and personal information protection matters.","Case 2: Although a working group for information protection and personal information protection was established, including heads of departments that handle important information and personal data, it has not been active for an extended period.","Case 3: Although the Information Protection and Personal Information Protection Committee was convened, major matters such as the annual information protection and personal information protection plan, training plan, budget, and personnel were not reviewed or decided upon.","Case 4: Although an Information Protection Committee was established for deliberation and decision-making on information protection and personal information protection matters, only the operations and IT security departments participated, without the involvement of departments responsible for personal information protection, leaving personal information protection matters undecided."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The CEO must establish and operate a working group to effectively implement information protection and personal information protection, a committee that can review and approve key matters related to information protection and personal information protection across the organization, and a consultative body consisting of department-level information protection and personal information protection officers for enterprise-wide protection activities.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.1.4": {"name": "Scope Setting","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.4 Scope Setting","Subdomain": "1.1. Management System","AuditEvidence": ["Scope definition document for information protection and personal information protection management system","List of information assets and personal information","Document list","Service flowchart","Personal information flowchart","Organization-wide organizational chart","System and network configuration diagram"],"AuditChecklist": ["Has the organization set the scope of the management system to include key assets that may affect core services and personal information processing?","If there are exceptions within the defined scope, are clear reasons documented, and are consultations with relevant stakeholders and approvals from responsible parties recorded and managed?","Is the organization maintaining documentation that includes the major services, operational status, and systems, allowing for clear verification of the scope of the information protection and personal information protection management system?"],"NonComplianceCases": ["Case 1: The development and test systems, external staff, PCs, and test devices related to the development work for information systems and personal information processing systems were omitted from the management system's scope.","Case 2: Key organizations (personnel) in departments and business units that play critical roles in decision-making for services or businesses within the scope of the information protection and personal information protection management system were not included in the certification scope.","Case 3: The development and test systems, developer PCs, test devices, and development organizations related to the development work for information systems and personal information processing systems were omitted from the management system's scope."],"RelatedRegulations": []}],"description": "The organization must set the scope of the management system by considering its core services and the current state of personal information processing, and document the related services, personal information processing tasks, organizations, assets, and physical locations.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.1.5": {"name": "Policy Establishment","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.5 Policy Establishment","Subdomain": "1.1. Management System","AuditEvidence": ["Information protection and personal information protection policies/guidelines/procedures (including records of new/revised versions)","Meeting minutes of stakeholder reviews of newly established/revised information protection and personal information protection policies/guidelines/procedures","Internal management plans for personal information","Notifications of new/revised information protection and personal information protection policies/guidelines (via groupware, intranet, etc.)","Minutes of the Information Protection and Personal Information Protection Committee"],"AuditChecklist": ["Has the organization established a top-level information protection and personal information protection policy that serves as the foundation for all information protection and personal information protection activities?","Has the organization established detailed guidelines, procedures, and manuals specifying the methods, processes, and frequencies required to implement the information protection and personal information protection policies?","Are the information protection and personal information protection policies and implementation documents approved by the CEO or by someone delegated by the CEO when newly established or revised?","Are the latest versions of the information protection and personal information protection policies and implementation documents provided to relevant employees in an easily understandable format?"],"NonComplianceCases": ["Case 1: Although internal regulations stipulate that revisions to the information protection and personal information protection policies must be approved by the Information Protection and Personal Information Protection Committee, recent revisions were made solely based on the approval of the CISO and CPO without presenting the revisions to the committee.","Case 2: The information protection and personal information protection policies and guidelines were recently revised, but these changes were not communicated to relevant departments and employees, leading some departments to continue operating based on outdated guidelines.","Case 3: The information protection and personal information protection policies and guidelines are managed solely by the security department and are not made available for employees to access through bulletin boards or documents."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The organization must establish and document information protection and personal information protection policies and implementation documents, clearly stating the organization's information protection and personal information protection guidelines and direction. These policies and implementation documents must be approved by the executive management and communicated in an understandable form to employees and relevant parties.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.1.6": {"name": "Resource Allocation","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.1.6 Resource Allocation","Subdomain": "1.1. Management System","AuditEvidence": ["Annual action plan for information protection and personal information protection activities (including budget and personnel plans)","Reports on the results of information protection and personal information protection activities","Records of investments in information protection and personal information protection","Information protection and personal information protection organization chart"],"AuditChecklist": ["Has the organization secured personnel with expertise in the fields of information protection and personal information protection?","Has the organization evaluated and allocated the necessary resources, including budget and personnel, for the effective implementation and continuous operation of the information protection and personal information protection management system?","Has the organization established and implemented an annual detailed action plan for information protection and personal information protection, and conducted audits, analyses, and evaluations of the results?"],"NonComplianceCases": ["Case 1: The organization assembled an information protection and personal information protection team, but the team consisted only of personnel without expertise in information protection or IT, resulting in inadequate security staffing.","Case 2: The CEO failed to allocate sufficient resources, such as budget and security solutions, for implementing the technical and managerial safeguards required for personal information processing systems.","Case 3: After obtaining certification, the organization significantly reduced personnel and budget support, reassigned existing staff to other departments, and repurposed part of the budget for other uses."],"RelatedRegulations": []}],"description": "The CEO must allocate the necessary resources, including budget and personnel with expertise in the fields of information protection and personal information protection, for the effective implementation and continuous operation of the management system.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.2.1": {"name": "Identification of Information Assets","checks": {"macie_is_enabled": "PASS","resourceexplorer2_indexes_found": "PASS","config_recorder_all_regions_enabled": null,"organizations_account_part_of_organizations": null,"organizations_tags_policies_enabled_and_attached": null},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.2.1 Identification of Information Assets","Subdomain": "1.2. Risk Management","AuditEvidence": ["Information asset and personal information asset classification criteria","Information asset and personal information asset list (from asset management system screen)","Information asset and personal information security levels","Asset audit details","Risk analysis report (including asset identification)"],"AuditChecklist": ["Has the organization established classification criteria for information assets and identified all assets within the scope of the information protection and personal information protection management system, maintaining them in a list?","For the identified information assets, does the organization determine their importance by considering legal requirements and their impact on operations, and assign security levels?","Does the organization regularly review the status of information assets to keep the list up-to-date?"],"NonComplianceCases": ["Case 1: The list of assets within the scope of the information protection and personal information protection management system omits internal information leakage control systems, such as print security, document encryption, and USB media control, which are used to manage PCs handling important information and personal information.","Case 2: Personal information provided by third parties within the scope of the information protection and personal information protection management system has not been identified as an asset.","Case 3: The asset classification criteria in the internal guidelines and the classification criteria in the asset management register are inconsistent.","Case 4: Although on-premises assets have been identified, assets related to externally entrusted IT services (web hosting, server hosting, cloud, etc.) have been omitted (only for assets within the certification scope).","Case 5: The backup server storing unique identification information and other personal data has been classified with a low confidentiality rating, raising concerns about the reasonableness and reliability of the importance assessment."],"RelatedRegulations": []}],"description": "Organizations must establish classification criteria for information assets according to the characteristics of their operations, identify and classify all information assets within the scope of the management system, assess their importance, and maintain an up-to-date list.","checks_status": {"fail": 0,"pass": 2,"total": 5,"manual": 0}},"1.2.2": {"name": "Status and Flow Analysis","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.2.2 Status and Flow Analysis","Subdomain": "1.2. Risk Management","AuditEvidence": ["Information service status table","Information service workflow charts and process maps","Personal information processing status table (for ISMS-P certification)","Personal information flowcharts (for ISMS-P certification)"],"AuditChecklist": ["Has the organization identified and documented the status and workflows of information services across all areas of the management system?","Has the organization identified and documented the status of personal information processing within the scope of the management system, and mapped out personal information flows in flowcharts?","Does the organization regularly review procedures and workflows in response to changes in services, operations, and information assets, and keep the flowcharts and related documents up-to-date?"],"NonComplianceCases": ["Case 1: There are no documents outlining the workflows and procedures for major services within the scope of the management system.","Case 2: The personal information flowchart contains significant discrepancies from the actual personal information flow, or important personal information flows are missing.","Case 3: After the initial creation of the personal information flowchart, it has not been updated to reflect changes in the personal information flow."],"RelatedRegulations": []}],"description": "Organizations must analyze the status of information services and personal information processing across all areas of the management system, document the procedures and workflows, and review them regularly to maintain their accuracy.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.2.3": {"name": "Risk Assessment","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.2.3 Risk Assessment","Subdomain": "1.2. Risk Management","AuditEvidence": ["Risk management guidelines","Risk management manuals/guides","Risk management plan","Risk assessment report","Minutes of the Information Protection and Personal Information Protection Committee","Minutes of the Information Protection and Personal Information Protection Working Group","Information asset and personal information asset list","Information service and personal information flowcharts"],"AuditChecklist": ["Has the organization defined methods for identifying and assessing risks that could arise from various aspects, depending on the characteristics of the organization or service?","Does the organization annually develop a risk management plan that specifies the personnel, timeline, targets, methods, and budget for risk management activities?","Does the organization conduct regular or ad-hoc risk assessments at least once a year according to the risk management plan?","Has the organization established an acceptable target risk level and identified risks that exceed that level?","Are the results of risk identification and assessment reported to the executives?"],"NonComplianceCases": ["Case 1: The risk management plan specifies the risk assessment period and the targets and methods for risk management, but lacks details on the personnel and budget required for execution.","Case 2: While a risk assessment was conducted in the previous year, no risk assessment was conducted this year due to a lack of changes in assets.","Case 3: The organization conducted risk identification and assessment according to the risk management plan, but failed to assess the risks of important information assets within the scope, or failed to assess compliance with legal requirements related to information protection.","Case 4: The organization identified and assessed risks and set an acceptable target risk level according to the risk management plan, but did not report and seek approval from the executives (e.g., the Chief Information Security Officer).","Case 5: The method defined in the internal guidelines for risk assessment differs from the method actually used.","Case 6: The organization failed to identify and assess risks in the administrative and physical areas related to the information protection management system, and used only the results of technical vulnerability assessments as the risk assessment outcome.","Case 7: The organization set the acceptable target risk level (DoA) unreasonably high, designating risks that required action as acceptable risks, even though these risks were significant and required immediate or short-term action."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "Organizations must collect threat information by analyzing internal and external environments, select a risk assessment method suitable for the organization, conduct a risk assessment at least once a year across all areas of the management system, and manage acceptable risks with the approval of the executives.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.2.4": {"name": "Selection of Protective Measures","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.2.4 Selection of Protective Measures","Subdomain": "1.2. Risk Management","AuditEvidence": ["Information protection and personal information protection implementation plans/risk management plans","Information protection and personal information protection measures","Information protection and personal information protection master plan","Records of management reports and approvals for the information protection and personal information protection implementation plan"],"AuditChecklist": ["Has the organization developed risk treatment strategies (e.g., risk reduction, avoidance, transfer, acceptance) and selected protective measures to address the identified risks?","Has the organization established and reported to management an implementation plan that includes priority, schedule, responsible department/personnel, and budget for the protective measures?"],"NonComplianceCases": ["Case 1: Although an implementation plan for the information protection and personal information protection measures was established, it was not reported to the CISO and CPO.","Case 2: Some risk mitigation actions that were required were missing from the implementation plan.","Case 3: Mandatory legal requirements and risks with high security vulnerabilities were accepted without additional protective measures, instead of being addressed by a risk treatment plan.","Case 4: The rationale and validity for risk acceptance were insufficient, and some risks that could have been addressed immediately or in the short term due to urgency or ease of implementation were classified under long-term plans without specific justification."],"RelatedRegulations": []}],"description": "Based on the results of the risk assessment, appropriate protective measures must be selected to address the identified risks, and an implementation plan including the priority, schedule, responsible department/personnel, and budget for the protective measures must be established and approved by management.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.3.1": {"name": "Implementation of Protective Measures","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.3.1 Implementation of Protective Measures","Subdomain": "1.3. Operation of the Management System","AuditEvidence": ["Information protection and personal information protection implementation plans/risk management plans","Information protection and personal information protection measures","Information protection and personal information protection implementation progress reports (including reports to management)","Information protection and personal information protection implementation completion reports (including reports to management)","Information protection and personal information protection operating statements"],"AuditChecklist": ["Are the protective measures effectively implemented according to the implementation plan, and are the implementation results reported to management to verify their accuracy and effectiveness?","Has the organization created and documented detailed operating statements recording the implementation and operation status of protective measures according to the certification standards of the management system?"],"NonComplianceCases": ["Case 1: The results of the completion of the information protection and personal information protection measures were not reported to the CISO and CPO.","Case 2: The risk action implementation result report indicated 'completed,' but related risks still existed, or the accuracy and effectiveness of the implementation results were not verified.","Case 3: Risks classified as medium- to long-term in the previous year's information protection measures implementation plan were not implemented in the current year, or the results were not reviewed and verified by management.","Case 4: The actual operating status described in the operating statements did not match reality, and related documents, approvals, and meeting minutes mentioned in the operating statements did not exist.","Case 5: Although the implementation results were reported to the CISO and CPO, some incomplete items were not followed up with reasons and corrective actions."],"RelatedRegulations": []}],"description": "The selected protective measures must be effectively implemented according to the implementation plan, and management must verify the accuracy and effectiveness of the implementation results.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.3.2": {"name": "Sharing of Protective Measures","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.3.2 Sharing of Protective Measures","Subdomain": "1.3. Operation of the Management System","AuditEvidence": ["List of operating or implementing departments for each protective measure","Evidence of internal sharing of information protection and personal information protection plans (e.g., notices, training materials, shared documents)"],"AuditChecklist": ["Has the organization clearly identified the departments and personnel responsible for the operation or implementation of the protective measures?","Has the organization shared or provided training to the departments and personnel responsible for the operation or implementation of the protective measures?"],"NonComplianceCases": ["Case 1: Although protective measures were developed and implemented, the relevant information was not sufficiently shared or provided through training, so the departments or personnel responsible for the actual operation or implementation were unaware of the details."],"RelatedRegulations": []}],"description": "The departments and personnel responsible for the actual operation or implementation of the protective measures must be identified, and the related information must be shared and provided through training to ensure continuous operation.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.3.3": {"name": "Operation Status Management","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.3.3 Operation Status Management","Subdomain": "1.3. Operation of the Management System","AuditEvidence": ["Annual plan for information protection and personal information protection","Operation status report for information protection and personal information protection","Results of inspections on the implementation of information protection and personal information protection activities"],"AuditChecklist": ["Are information protection and personal information protection activities that need to be performed periodically or continuously for the operation of the management system documented and managed?","Does management periodically review the effectiveness of the operation of the management system and manage it accordingly?"],"NonComplianceCases": ["Case 1: Failure to document activities that are required to be performed periodically or continuously as part of the operation of the information protection and personal information protection management system.","Case 2: Although documentation of the operational status of the information protection and personal information protection management system has been completed, periodic reviews have not been conducted, resulting in the omission of some required monthly and quarterly activities, and some activities have not been verified for implementation."],"RelatedRegulations": ["Personal Information Protection Act, Article 31 (Designation of a Personal Information Protection Officer)","Information and Communications Network Act, Article 45-3 (Designation of a Chief Information Security Officer, etc.)"]}],"description": "According to the management system established by the organization, operational activities that must be performed continuously or periodically must be recorded and managed in a way that allows identification and tracking, and management must regularly review the effectiveness of operational activities and manage them accordingly.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.4.1": {"name": "Review of Legal Requirements Compliance","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.4.1 Review of Legal Requirements Compliance","Subdomain": "1.4. Inspection and Improvement of the Management System","AuditEvidence": ["Records of legal compliance reviews","Records of reviews and revisions of information protection and personal information protection policies and guidelines","Comparison tables of revised policies and guidelines","Internal sharing documents of legal revisions","Proof of personal information liability insurance or equivalent guarantees (e.g., cyber insurance contracts)","Information protection disclosure records"],"AuditChecklist": ["Is the organization regularly identifying and maintaining up-to-date legal requirements related to information protection and personal information protection?","Is the organization conducting regular reviews of compliance with legal requirements at least once a year?"],"NonComplianceCases": ["Case 1: Although the Information and Communications Network Act and Personal Information Protection Act were recently revised, the organization did not review the impact of the changes on the organization, and as a result, the policy documents, implementation documents, and legal compliance checklists were not updated, leading to inconsistencies between the documents and the law.","Case 2: Although legal requirements that the organization must comply with were amended, the organization failed to conduct legal compliance reviews for an extended period.","Case 3: Inadequate legal compliance reviews resulted in numerous violations of the Personal Information Protection Act and other regulations.","Case 4: The organization was subject to the Personal Information Liability Compensation Guarantee system under the Personal Information Protection Act but failed to recognize this, resulting in non-compliance with insurance or reserve requirements. In cases where insurance was obtained, the organization failed to meet the minimum coverage requirements based on the number of users and revenue.","Case 5: Although the organization was required by law to disclose information protection status, it failed to do so within the legally mandated timeframe.","Case 6: The organization used a mobile app to receive personal location information from a location-based service provider, but failed to report its location-based service business.","Case 7: A foreign personal information controller without a domestic address or business office, whose personal information of domestic subjects stored and managed in the previous three months averaged over one million persons per day, failed to appoint a domestic representative in writing as required."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The organization must regularly identify and reflect legal requirements related to information protection and personal information protection and continuously review whether compliance is being maintained.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.4.2": {"name": "Management System Audit","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.4.2 Management System Audit","Subdomain": "1.4. Inspection and Improvement of the Management System","AuditEvidence": ["Management system audit plan (internal audit plan, internal inspection plan)","Management system audit report","Minutes of the Information Protection and Personal Information Protection Committee"],"AuditChecklist": ["Has the organization established a management system audit plan that includes the criteria, scope, frequency, and qualifications for audit personnel to audit the management system's effectiveness in accordance with legal requirements and established policies?","Has the organization conducted audits at least once a year with personnel who have independence, objectivity, and expertise, and reported any identified issues to management?"],"NonComplianceCases": ["Case 1: The audit team included personnel from the IT department, which was also the subject of the audit, compromising the independence of the audit.","Case 2: Although a management system audit was conducted this year, the audit scope was limited to certain areas, failing to cover the full scope of the information protection and personal information protection management system.","Case 3: The management system audit team was composed solely of internal staff and external consultants who participated in the development of the management system, compromising the independence of the audit."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The organization must audit its management system at least once a year with a team of personnel who possess independence and expertise, to ensure the system is operating effectively in accordance with internal policies and legal requirements, and report any identified issues to management.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.4.3": {"name": "Management System Improvement","checks": {},"status": "PASS","attributes": [{"Domain": "1. Establishment and Operation of the Management System","Section": "1.4.3 Management System Improvement","Subdomain": "1.4. Management System Inspection and Improvement","AuditEvidence": ["Management system inspection result reports","Management system inspection action plans and implementation result reports","Preventive measures","Effectiveness measurement indicators and results (including reports to management)"],"AuditChecklist": ["Are the root causes of the issues identified during legal compliance reviews and management system inspections analyzed, and are preventive and improvement measures established and implemented?","Are there criteria and procedures in place to verify the accuracy and effectiveness of preventive and improvement results?"],"NonComplianceCases": ["Case 1: The same issues in the operation of the information protection and personal information protection management system, identified during internal inspections, are repeated each time.","Case 2: Although internal regulations require the analysis of root causes and the establishment of preventive measures for issues identified during internal inspections, recent internal inspections failed to include root cause analysis and preventive measures.","Case 3: Preventive measures for the issues in the management system were established, and key performance indicators (KPIs) were developed for periodic measurement, but the results were not reported to management for a long period.","Case 4: Action plans were not established or the completion of actions was not confirmed for issues identified during management system inspections."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "The root causes of the issues identified during legal compliance reviews and management system inspections must be analyzed, and preventive measures must be established and implemented. The management must confirm the accuracy and effectiveness of the improvement results.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.1.1": {"name": "Policy Maintenance","checks": {},"status": "PASS","attributes": [{"Domain": "2. Control Measures Requirements","Section": "2.1.1 Policy Maintenance","Subdomain": "2.1. Policies, Organization, and Asset Management","AuditEvidence": ["Information protection and personal information protection policies and implementation documents (e.g., guidelines, procedures, manuals)","Results of regular and ad hoc validity reviews of policies and guidelines","Meeting minutes and circulation records with relevant departments regarding policies and guidelines","Revision history of policies and guidelines"],"AuditChecklist": ["Has the organization established and implemented a procedure for regularly reviewing the validity of information protection and personal information protection policies and implementation documents?","When there are significant changes in the internal and external environment, are the impacts on information protection and personal information protection policies and implementation documents reviewed and revised as necessary?","Are stakeholders consulted when revising information protection and personal information protection policies and implementation documents?","Is there a system in place to track the revision history of information protection and personal information protection policies and implementation documents?"],"NonComplianceCases": ["Case 1: There is inconsistency between password setting rules in guidelines and procedures.","Case 2: Information protection activities (e.g., training, encryption, backup) have different targets, frequencies, levels, and methods described in internal regulations, guidelines, and procedures, leading to inconsistency.","Case 3: A new database access control solution was introduced to effectively record and manage access and operation logs for the database, but internal security guidelines such as those for security systems and database security management have not been updated to reflect these new controls.","Case 4: Although the personal information protection policy was revised, the policy implementation date was not specified, and information such as the author, creation date, and approval date were missing from the relevant policy.","Case 5: Although significant changes occurred in laws and regulations related to personal information protection, these changes were not reviewed or reflected in the personal information protection policy and implementation documents."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "Information protection and personal information protection policies and implementation documents must be periodically reviewed and, if necessary, revised in response to changes in laws and regulations, policies of higher organizations and related agencies, and changes in the internal and external environment. These changes must be documented and tracked.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.1.2": {"name": "Organization Maintenance","checks": {},"status": "PASS","attributes": [{"Domain": "2. Control Measures Requirements","Section": "2.1.2 Organization Maintenance","Subdomain": "2.1. Policies, Organization, and Asset Management","AuditEvidence": ["Information protection and personal information protection organization chart","Job descriptions for the information protection and personal information protection organization","Assignment tables for information protection and personal information protection roles","Information protection and personal information protection policies/guidelines and internal management plans","Information protection and personal information protection communication management plans","Records of communication activities (e.g., monthly/weekly reports, internal notices)","Communication channels (e.g., information protection portal, bulletin boards)"],"AuditChecklist": ["Are the roles and responsibilities of those responsible for and involved in information protection and personal information protection clearly defined?","Has the organization established a system for evaluating the activities of those responsible for and involved in information protection and personal information protection?","Has the organization established and implemented systems and procedures for communication between the information protection and personal information protection organization and its members?"],"NonComplianceCases": ["Case 1: Although the roles and responsibilities of the CISO, CPO, and related personnel are defined in internal guidelines and job descriptions, they do not align with the actual operating status.","Case 2: There are no goals, criteria, or performance indicators in place for the periodic evaluation of the activities of the CISO and related personnel.","Case 3: Although internal guidelines require departments to set KPIs related to information protection for the information protection officers in each department to be reflected in performance evaluations, no information protection-related KPIs were set for any of the departmental information protection officers.","Case 4: Although the CISO and CPO are designated, the roles and responsibilities required by law are not specifically defined in internal guidelines or job descriptions."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures), Article 31 (Designation of a Personal Information Protection Officer)","Information and Communications Network Act, Article 45-3 (Designation of a Chief Information Security Officer, etc.)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "Roles and responsibilities related to information protection and personal information protection must be assigned to all members of the organization, and systems must be established for evaluating these activities and for communication between members and departments.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.1.3": {"name": "Management of Information Assets","checks": {"macie_is_enabled": "PASS","resourceexplorer2_indexes_found": "PASS","config_recorder_all_regions_enabled": null,"account_maintain_current_contact_details": null,"organizations_account_part_of_organizations": null,"organizations_tags_policies_enabled_and_attached": null,"account_security_contact_information_is_registered": null,"account_security_questions_are_registered_in_the_aws_account": null,"account_maintain_different_contact_details_to_security_billing_and_operations": null},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.1.3 Management of Information Assets","Subdomain": "2.1. Policy, Organization, Asset Management","AuditEvidence": ["List of information assets (designation of responsible persons and managers)","Handling procedures for information assets (documents, information systems, etc.)","Information asset management system screen","Security classification indicators for information assets"],"AuditChecklist": ["Are handling procedures (creation, introduction, storage, use, disposal) and protection measures defined and implemented according to the security classification of information assets?","Have responsible persons and managers been designated for identified information assets?"],"NonComplianceCases": ["Case 1: Although internal guidelines require security classification to be indicated on documents, this has not been followed.","Case 2: Responsible persons and managers for information assets have not been identified, or the asset list has not been updated, leading to changes in responsible personnel due to resignations, transfers, etc., not being reflected.","Case 3: Although security classifications were assigned to identified information assets after evaluating their importance, handling procedures based on the security classification were not defined."],"RelatedRegulations": []}],"description": "The procedures and protection measures for handling information assets according to their purpose and importance must be established and implemented, and the responsibilities for each asset must be clearly defined and managed.","checks_status": {"fail": 0,"pass": 2,"total": 9,"manual": 0}},"2.2.1": {"name": "Designation and Management of Key Personnel","checks": {"iam_support_role_created": null,"organizations_delegated_administrators": null,"account_security_contact_information_is_registered": null},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.2.1 Designation and Management of Key Personnel","Subdomain": "2.2. Personnel Security","AuditEvidence": ["Criteria for key duties","List of key personnel","List of personal information handlers","Account and authority management ledger for key information systems and personal information processing systems","Management status of key personnel (e.g., training results, security pledges)"],"AuditChecklist": ["Are the criteria for key duties, such as handling personal information and important information or accessing key systems, clearly defined?","Are employees and external personnel performing key duties designated as key personnel, and is the list kept up-to-date?","Are personnel handling personal information designated as personal information handlers, and is the list kept up-to-date?","Is the designation of key personnel and personal information handlers minimized based on business needs, and are management plans established and implemented?"],"NonComplianceCases": ["Case 1: Although a list of key personnel (e.g., personal information handlers, secret information managers) has been created, some employees who handle large volumes of personal information (e.g., DBAs, DLP managers) were omitted.","Case 2: Although the list of key personnel and personal information handlers is being managed, it has not been updated, including resigned employees and newly hired personnel.","Case 3: Personal information handler privileges were granted collectively to entire departments, leading to personnel without the need to handle personal information being excessively designated as personal information handlers.","Case 4: Although internal guidelines require approval from the security team and the signing of security pledges when granting key personnel privileges, many key personnel were registered without following this process."],"RelatedRegulations": ["Personal Information Protection Act, Article 28 (Supervision of Personal Information Handlers), Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "Criteria and management plans for key duties, such as handling personal information and important information or accessing key systems, must be established, and the number of key personnel must be minimized and their list kept up-to-date.","checks_status": {"fail": 0,"pass": 0,"total": 3,"manual": 0}},"2.2.2": {"name": "Separation of Duties","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.2.2 Separation of Duties","Subdomain": "2.2. Personnel Security","AuditEvidence": ["Guidelines on the separation of duties (e.g., personnel security guidelines)","Job descriptions (e.g., system operation/management, development/operation)","Status of supplementary controls when duties are not separated"],"AuditChecklist": ["Are criteria for the separation of duties established and applied to prevent potential harm from the misuse or abuse of authority?","If separation of duties is difficult, have supplementary controls such as mutual review between personnel, regular monitoring and approval of changes by senior management, and ensuring accountability been established?"],"NonComplianceCases": ["Case 1: Although the organization has sufficient size and personnel to enable separation of duties, the established internal separation of duties criteria were not followed due to operational convenience.","Case 2: Although the organization received approval from senior management to combine development and operation duties due to the organization's characteristics, supplementary control measures such as mutual review between personnel, regular monitoring and review of changes by senior management, and ensuring accountability were not established."],"RelatedRegulations": []}],"description": "Criteria for the separation of duties must be established and applied to prevent potential harm from the misuse or abuse of authority. If separation of duties is unavoidable, supplementary measures must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.2.3": {"name": "Security Pledge","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.2.3 Security Pledge","Subdomain": "2.2. Human Security","AuditEvidence": ["Security and personal information protection pledge (for employees and external personnel)","Confidentiality agreement (for resigned employees)"],"AuditChecklist": ["When hiring new personnel, is there a signed security and personal information protection agreement that specifies their responsibilities?","If temporary or external personnel are granted access to information assets, is there a signed agreement outlining their responsibilities for information protection and confidentiality?","Upon the resignation of an employee, is a separate confidentiality agreement obtained?","Are security, personal information protection, and confidentiality agreements stored safely and managed in a way that they can be easily retrieved when necessary?"],"NonComplianceCases": ["Case 1: While it is stipulated that new hires must sign a security pledge, some recently hired employees have not completed the pledge.","Case 2: Although employees sign a security pledge, external personnel with direct access to information systems have not signed such an agreement.","Case 3: Submitted security and personal information protection pledges are poorly managed, with documents left accessible on desks where unauthorized personnel can access them.","Case 4: Although personal information handlers have signed security pledges, the content only covers confidentiality and does not include specific responsibilities related to personal information protection."],"RelatedRegulations": []}],"description": "Employees, temporary staff, or external personnel handling information assets or granted access must sign a security and confidentiality agreement in accordance with internal policies.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.2.4": {"name": "Awareness and Training","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.2.4 Awareness and Training","Subdomain": "2.2. Human Security","AuditEvidence": ["Information protection and personal information protection training plan","Training result report","General and job-specific training materials","List of training attendees"],"AuditChecklist": ["Is an annual training plan approved by management, detailing the timing, duration, target audience, content, and method of information protection and personal information protection training?","Are all employees and external personnel within the scope of the management system provided with regular training at least once per year, and are additional training sessions provided when there are significant changes in relevant laws and regulations?","Is information protection and personal information protection training provided to new hires and external personnel before they begin their duties?","Are IT, information protection, and personal information protection staff receiving specialized training to enhance their job-specific expertise?","Are training records maintained, and is the effectiveness of the training evaluated and reflected in future training plans?"],"NonComplianceCases": ["Case 1: Although an annual information protection and personal information protection training plan was established and implemented last year, no such plan was established for the current year without a valid reason.","Case 2: The annual information protection and personal information protection training plan includes the frequency and target audience but lacks details such as schedule, content, and method.","Case 3: Although the annual training plan includes general personal information awareness training for all employees, it does not include job-specific training for those responsible for personal information protection, such as the personal information protection officer.","Case 4: Upon reviewing the training plan and result reports, it was found that certain external contractors (e.g., cleaning staff and security guards who have access to critical facilities within the certification scope) were not included in the training.","Case 5: Although information protection and personal information protection training was conducted, some records (e.g., training materials, attendance lists, evaluation surveys, result reports) were not retained.","Case 6: There is no system in place to identify employees who did not complete the required training or to provide make-up sessions for them (e.g., additional training, online courses)."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Limitation on the Processing of Personal Information by Outsourcing), Article 28 (Supervision of Personal Information Handlers), Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans)"]}],"description": "Organizations must establish and operate an annual awareness and training plan to ensure that employees and related external personnel understand the organization's management system and policies and acquire the necessary job-specific expertise. The effectiveness of this plan must be evaluated and reflected in future plans.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.2.5": {"name": "Management of Resignation and Job Changes","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.2.5 Management of Resignation and Job Changes","Subdomain": "2.2. Human Security","AuditEvidence": ["Procedures for resignation and job changes","Asset (account) return management ledger upon resignation","Security checklists and inspection records for resigned employees"],"AuditChecklist": ["Are personnel changes (e.g., resignation, job changes, department transfers, leave of absence) shared among HR, information protection, personal information protection, and IT system operations departments?","Are procedures in place and implemented to promptly return information assets, revoke or adjust access rights, and confirm results when an employee (including temporary staff and external contractors) resigns or changes roles?"],"NonComplianceCases": ["Case 1: Accounts and access rights for personnel no longer handling personal information due to job changes remain active in the personal information processing system.","Case 2: No records of asset returns or access rights revocation procedures were found for recently resigned key personnel and personal information handlers.","Case 3: While asset returns are properly managed for resigned employees, the security check and resignation confirmation forms required by HR regulations are not being completed.","Case 4: Although access rights to personal information processing systems were revoked promptly upon the resignation of personal information handlers, access rights to systems like physical access control and VPN were not revoked in a timely manner."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "Procedures must be established and managed for the return of assets, the revocation or adjustment of accounts and access rights, and confirmation of results when there is a resignation, job change, or leave of absence, involving departments such as HR, information protection, personal information protection, and IT.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.2.6": {"name": "Actions in Case of Security Violations","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.2.6 Actions in Case of Security Violations","Subdomain": "2.2. Human Security","AuditEvidence": ["HR regulations (disciplinary measures for violations of information protection and personal information protection regulations)","Records of disciplinary actions for violations of information protection and personal information protection guidelines","Incident case studies (company-wide notices, training materials)"],"AuditChecklist": ["Has the organization established disciplinary measures for employees and relevant external parties in case of violations of information protection and personal information protection responsibilities and obligations under laws, regulations, and internal policies?","When violations of information protection and personal information protection are detected, are actions taken in accordance with internal procedures?"],"NonComplianceCases": ["Case 1: No disciplinary measures or procedures are included in internal regulations for handling violations of information protection and personal information protection regulations.","Case 2: Although warning messages are sent to those who violate policies detected by security systems (e.g., DLP, database access control system, internal information leakage control system), follow-up actions such as explanations, additional investigations, or disciplinary actions are not carried out in accordance with internal regulations."],"RelatedRegulations": []}],"description": "In the event that employees or relevant external parties violate laws, regulations, or internal policies, the organization must establish and implement procedures to take appropriate actions.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.3.1": {"name": "Management of External Parties","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.3.1 Management of External Parties","Subdomain": "2.3. External Security","AuditEvidence": ["List of outsourced services and external facilities/services","Outsourcing contracts","Risk analysis reports and protective measures","Outsourcing security management guidelines, checklists, etc."],"AuditChecklist": ["Has the organization identified the status of outsourcing and the use of external facilities and services within the scope of the management system?","Has the organization identified the legal requirements and risks associated with outsourcing and the use of external facilities and services, and established appropriate protective measures?"],"NonComplianceCases": ["Case 1: Although the organization manages a list of outsourced services and external facilities/services as required by internal regulations, the list is outdated and does not reflect changes made to vendors several months ago.","Case 2: The organization has migrated some personal information processing systems to external cloud services within the scope of the management system, but no identification or risk assessment has been performed."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Restrictions on the Processing of Personal Information by Outsourcing)","Information and Communications Network Act, Article 50-3 (Entrustment of the Transmission of Commercial Information for Profit)"]}],"description": "When outsourcing part of the work (e.g., handling personal information, information protection, operating or developing information systems) or using external facilities or services (e.g., data centers, cloud services, application services), the organization must identify the current status, understand the legal requirements and risks arising from external organizations or services, and establish appropriate protective measures.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.3.2": {"name": "Security in Contracts with External Parties","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.3.2 Security in Contracts with External Parties","Subdomain": "2.3. External Security","AuditEvidence": ["Outsourcing contracts","Information protection and personal information protection agreements (agreements, annexes)","Internal guidelines on outsourcing","RFPs (Requests for Proposals), evaluation forms related to the selection of outsourcing vendors"],"AuditChecklist": ["When selecting external services or outsourcing vendors related to the handling of important information and personal information, does the organization follow procedures to consider the vendors' capabilities in information protection and personal information protection?","Has the organization identified the information protection and personal information protection requirements associated with the use of external services and outsourcing, and specified them in contracts or agreements?","When outsourcing the development of information systems and personal information processing systems, has the organization specified the information protection and personal information protection requirements that must be followed during development in the contract?"],"NonComplianceCases": ["Case 1: No outsourcing contract exists for external vendors performing IT operations, development, or personal information processing tasks.","Case 2: The outsourcing contract with an external vendor handling personal information does not include some items required by the Personal Information Protection Act (e.g., management and supervision provisions).","Case 3: Although infrastructure operation and part of personal information processing tasks are outsourced to external vendors, the contract does not specify security requirements related to the nature of the outsourced work, but only includes general provisions on confidentiality and liability for damages."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Restrictions on the Processing of Personal Information by Outsourcing)"]}],"description": "When using external services or outsourcing work to external parties, the organization must identify the information protection and personal information protection requirements and specify them in contracts or agreements.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.3.3": {"name": "External Party Security Implementation Management","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.3.3 External Party Security Implementation Management","Subdomain": "2.3. External Party Security","AuditEvidence": ["Security inspection results for external parties and contractors","Training details for external parties and contractors (training outcomes, attendee list, training materials, etc.)","Personal information outsourcing contract","Evidence of consent for re-outsourcing of personal information processing tasks"],"AuditChecklist": ["Are periodic inspections or audits conducted to ensure external parties comply with information protection and personal information protection requirements specified in contracts, agreements, and internal policies?","When issues are identified during inspections or audits of external parties, are improvement plans established and implemented?","If a contractor entrusted with personal information processing re-outsources related tasks to a third party, does the contractor obtain the principal's consent?"],"NonComplianceCases": ["Case 1: Failure to regularly conduct security inspections of external contractors who perform IT development and operations tasks on-site.","Case 2: Sending a notification to contractors entrusted with personal information processing to conduct security training, but failing to verify whether the training has been conducted.","Case 3: Allowing contractors to perform their own security inspections and report the results, without a verification process to ensure the inspections were properly conducted, thus undermining the reliability of the inspection results.","Case 4: Allowing contractors to re-outsource personal information processing tasks to a third party without the principal's consent.","Case 5: Failure to supervise contractors entrusted with transmitting commercial information for profit."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Restrictions on the Outsourcing of Personal Information Processing)","Information and Communications Network Act, Article 50-3 (Outsourcing of the Transmission of Commercial Information for Profit)"]}],"description": "Security measures specified in contracts, agreements, and internal policies must be regularly inspected or audited to ensure external parties comply with information protection and personal information protection requirements.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.3.4": {"name": "Security for External Party Contract Changes and Expiry","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.3.4 Security for External Party Contract Changes and Expiry","Subdomain": "2.3. External Party Security","AuditEvidence": ["Information protection and personal information protection agreements","Confidentiality agreements","Information and personal information destruction agreements","Internal policies and guidelines related to the termination of external party contracts"],"AuditChecklist": ["Has the organization established and implemented security measures to ensure the return of information assets, deletion of information system access accounts, and the acquisition of confidentiality agreements in accordance with official procedures when an external party contract expires, a task is completed, or there is a personnel change?","When an external party contract expires, has the organization established and implemented procedures to confirm whether the external party holds any sensitive or personal information related to the outsourced task, and to retrieve or destroy such information?"],"NonComplianceCases": ["Case 1: Failure to delete accounts and permissions for external parties after their contract has expired, allowing access to certain information systems.","Case 2: During an outsourcing project, failure to take appropriate measures for some contractors who were replaced or whose contracts expired, including failing to obtain security agreements as required by internal regulations.","Case 3: After terminating a contract with a contractor entrusted with personal information processing, failure to verify whether the contractor destroyed any personal information they held."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Restrictions on the Outsourcing of Personal Information Processing)","Information and Communications Network Act, Article 50-3 (Outsourcing of the Transmission of Commercial Information for Profit)"]}],"description": "When an external party contract expires, the task is completed, or there is a personnel change, security measures such as returning provided information assets, deleting information system access accounts, destroying sensitive information, and obtaining confidentiality agreements for acquired information must be implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.1": {"name": "Designation of Protected Zones","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.4.1 Designation of Protected Zones","Subdomain": "2.4. Physical Security","AuditEvidence": ["Physical security guidelines (criteria for designating protected zones)","List of designated protected zones","Protected zone signage","List of protection measures for each zone"],"AuditChecklist": ["Has the organization established criteria for designating physical protection zones such as controlled areas, restricted areas, and reception areas to protect personal and sensitive information, documents, storage media, key facilities, and systems from physical and environmental threats?","Has the organization designated physical protection zones in accordance with the criteria and established and implemented protection measures for each zone?"],"NonComplianceCases": ["Case 1: Although internal physical security guidelines state that areas where personal information is stored and processed must be designated as controlled zones, certain document storage rooms containing membership application forms were omitted from the list of controlled zones.","Case 2: Internal physical security guidelines require that controlled zones be marked with specific signs, but some controlled zones do not have the required signage."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 10 (Physical Safety Measures)"]}],"description": "To protect personal and sensitive information, documents, storage media, key facilities, and systems from physical and environmental threats, physical protection zones such as controlled areas, restricted areas, and reception areas must be designated, and protection measures for each zone must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.2": {"name": "Access Control","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.4.2 Access Control","Subdomain": "2.4. Physical Security","AuditEvidence": ["Access logbook and entry logs","Access registration application form and approval records","Entry record review report","Access control system management screen (status of registered personnel, etc.)"],"AuditChecklist": ["Is access to protected areas controlled so that only authorized personnel are allowed to enter according to access procedures?","Are entry records for internal and external personnel for each protected area retained for a certain period, and are entry records and access permissions reviewed periodically?"],"NonComplianceCases": ["Case 1: Although control areas are defined, protective measures are established, and employees with access are managed, the entry records are not reviewed periodically, resulting in many inactive personnel (due to retirement, transfer, etc.) having long periods of no entry.","Case 2: Although access control devices are installed in controlled areas such as data centers and document storage rooms, they are left open for extended periods without valid reasons or approval.","Case 3: Some external partner employees are excessively granted all-area access cards for unrestricted entry."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 10 (Physical Safety Measures)"]}],"description": "Access to protected areas must be restricted to authorized personnel only, and entry and access logs should be reviewed periodically to ensure accountability.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.3": {"name": "Information System Protection","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.4.3 Information System Protection","Subdomain": "2.4. Physical Security","AuditEvidence": ["Data processing facility diagram","Information system layout","Asset list"],"AuditChecklist": ["Are information systems placed in separated locations based on their importance, usage, and characteristics?","Are there measures in place to easily verify the actual physical location of the information systems?","Are power and communication cables protected from physical damage and electrical interference from external sources?"],"NonComplianceCases": ["Case 1: The system layout is not updated to reflect the latest changes, making it difficult to quickly identify the information system that has experienced a failure.","Case 2: Many cables are tangled and not properly organized on the server room floor or in racks, increasing the risk of failure due to electrical interference, damage, leakage, or negligence."],"RelatedRegulations": []}],"description": "Information systems should be arranged considering their importance and characteristics to reduce environmental threats, harmful factors, and unauthorized access, and communication and power cables should be protected from damage.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.4": {"name": "Operation of Protective Facilities","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.4.4 Operation of Protective Facilities","Subdomain": "2.4. Physical Security","AuditEvidence": ["Physical security guidelines (related to protective facilities)","Data center facility status and inspection checklist","IDC outsourcing contract, SLA, etc."],"AuditChecklist": ["Are necessary facilities established and operational procedures set up based on the importance and characteristics of each protected area to prevent disasters such as fire, flood, and power failure caused by human error or natural disasters?","If operating outsourced integrated data centers (IDC), are physical security requirements included in the contract, and is the operational status periodically reviewed?"],"NonComplianceCases": ["Case 1: In some protected areas, such as the main office data center, the required protective facilities specified in internal guidelines are not installed.","Case 2: Although protective facilities such as UPS and fire suppression systems are in place in the data center, operational and inspection standards for the related facilities are not established.","Case 3: Although temperature and humidity control devices were installed in the data center according to operational guidelines, insufficient capacity means that the standard temperature and humidity levels are not maintained, increasing the risk of failure."],"RelatedRegulations": ["Information and Communications Network Act, Article 46 (Protection of Integrated Data Centers)","Guidelines for the Protection of Integrated Data Centers","Fire Facility Installation and Management Act, Article 12 (Management of Fire Protection Facilities in Specific Fire Protection Objects), Article 16 (Management of Evacuation Facilities, Fire Zones, and Fire Protection Facilities)"]}],"description": "Based on the importance and characteristics of the information systems located in protected areas, protective facilities such as temperature and humidity control, fire detection, firefighting equipment, leak detection, UPS, emergency generators, and dual power lines should be established and operated according to operational procedures.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.5": {"name": "Operations in Secure Zones","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.4.5 Operations in Secure Zones","Subdomain": "2.4. Physical Security","AuditEvidence": ["Operation request forms, operation logs","Entry logs for controlled areas","Records of review of entry and operation logs for controlled areas"],"AuditChecklist": ["When operations within secure zones, such as the introduction and maintenance of information systems, are required, are formal procedures for application and execution of such operations established and implemented?","Are the records of operations within secure zones periodically reviewed to confirm that the operations were carried out in accordance with the control procedures?"],"NonComplianceCases": ["Case 1: The entry log of the data center shows the presence of external maintenance personnel, but there is no record of an operation request or approval for work within the secure zone (i.e., entry and work in the secure zone were carried out without an operation request as required by internal regulations).","Case 2: Although internal regulations state that the records of operations within secure zones must be reviewed at least once per quarter, the review of such records has not been conducted for a long period without a valid reason."],"RelatedRegulations": []}],"description": "Procedures to prevent unauthorized actions and abuse of privileges within secure zones must be established and implemented, and the records of operations should be periodically reviewed.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.6": {"name": "Device Control for Inbound and Outbound","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.4.6 Device Control for Inbound and Outbound","Subdomain": "2.4. Physical Security","AuditEvidence": ["Inbound and outbound application forms for secure zones","Inbound and outbound management logs","Results of the review of inbound and outbound records"],"AuditChecklist": ["Are control procedures established and implemented to prevent security incidents such as information leakage and malware infection when information systems, mobile devices, storage media, etc., are brought into or taken out of secure zones?","Are records maintained and managed in accordance with the inbound and outbound control procedures, and is the compliance with the procedures periodically checked by reviewing the history of inbound and outbound activities?"],"NonComplianceCases": ["Case 1: Although control procedures for the inbound and outbound of mobile computing devices are established, there is no control over the movement of such devices within the controlled area, allowing both internal and external personnel with access to the controlled area to use mobile computing devices without restriction.","Case 2: Although internal guidelines state that inbound and outbound details of IT equipment must be recorded in the operation plan and signed by the person responsible for management, many signatures of responsible managers are missing from the records."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 10 (Physical Safety Measures)"]}],"description": "Procedures to control the inbound and outbound movement of information systems, mobile devices, storage media, etc., within secure zones must be established, implemented, and periodically reviewed.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.4.7": {"name": "Work Environment Security","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.4.7 Work Environment Security","Subdomain": "2.4. Physical Security","AuditEvidence": ["Security inspection reports for offices and shared spaces","Security inspection checklists for offices and shared spaces","Actions taken for non-compliance (e.g., training, rewards and penalties)","Current status of protection measures for printed and copied materials"],"AuditChecklist": ["Are protection measures established and implemented for shared facilities and office equipment such as document storage, shared PCs, multifunction printers, file servers, etc.?","Are protection measures established and implemented to prevent the exposure or leakage of personal and sensitive information through individual work environments such as work PCs, desks, drawers, etc.?","Are appropriate protection measures in place to ensure the safe handling of printed or copied materials containing personal information, such as paper documents?","Is compliance with information protection requirements in both individual and shared work environments periodically reviewed?"],"NonComplianceCases": ["Case 1: Although the internal management plan for personal information specifies that regular security inspections (e.g., clean desk policies) must be conducted, no such inspections have been carried out.","Case 2: Documents containing personal information, such as membership application forms, are stored in an office cabinet without a lock.","Case 3: Employee computers do not have screen savers or passwords set, and important documents have been left on vacationing employees' desks for an extended period.","Case 4: No protection measures are in place for shared PCs installed in shared office spaces such as meeting rooms, resulting in personal information files being stored unencrypted, or security updates not applied, or antivirus software not installed, leaving the systems vulnerable."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 10 (Physical Safety Measures), Article 12 (Safety Measures for Printing and Copying)"]}],"description": "Protection measures such as clean desk policies and regular inspections must be established and implemented to prevent unauthorized exposure or leakage of personal and sensitive information through shared office equipment (e.g., document storage, shared PCs, multifunction printers, file servers) and individual work environments (e.g., work PCs, desks).","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.5.1": {"name": "User Account Management","checks": {"iam_user_accesskey_unused": null,"iam_securityaudit_role_created": null,"iam_user_console_access_unused": null,"iam_policy_no_full_access_to_kms": null,"iam_role_administratoraccess_policy": null,"iam_user_administrator_access_policy": null,"organizations_scp_check_deny_regions": null,"iam_group_administrator_access_policy": null,"iam_policy_allows_privilege_escalation": null,"iam_inline_policy_no_full_access_to_kms": null,"iam_policy_no_full_access_to_cloudtrail": null,"iam_policy_attached_only_to_group_or_roles": null,"cognito_user_pool_self_registration_disabled": null,"iam_role_cross_account_readonlyaccess_policy": null,"iam_inline_policy_allows_privilege_escalation": null,"iam_inline_policy_no_administrative_privileges": null,"iam_inline_policy_no_full_access_to_cloudtrail": null,"iam_no_custom_policy_permissive_role_assumption": null,"iam_role_cross_service_confused_deputy_prevention": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"iam_customer_unattached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.5.1 User Account Management","Subdomain": "2.5. Authentication and Access Management","AuditEvidence": ["User account and access request forms","User account and access management log or screen","Access classification table for information systems and personal information processing systems","Lists of users, administrators, and personal information handlers for each information system and personal information processing system"],"AuditChecklist": ["Has the organization established and implemented formal procedures for registering, changing, and deleting user accounts and access rights to information systems, personal information, and critical information?","When creating and registering user accounts and access rights to information systems, personal information, and critical information, is access limited to the minimum necessary for each job based on the job-specific access classification system?","When granting users accounts and access rights, are they made fully aware that they are responsible for the security of those accounts?"],"NonComplianceCases": ["Case 1: User registration, termination, and approval procedures for accounts and permissions for users and personal information handlers were processed through verbal requests, email, etc., without proper approval and handling records.","Case 2: A personal information handler shared their account with an unauthorized individual for backup purposes during vacations, business trips, or other absences without going through official procedures.","Case 3: Users of information systems or personal information processing systems were granted excessive permissions, allowing access to unnecessary information or personal data."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "To control unauthorized access to information systems, personal information, and critical information, organizations must establish and implement procedures for user registration, termination, and granting, changing, or revoking access rights, ensuring that access rights are granted only to the minimum necessary for work purposes. Additionally, when registering or granting user rights, it must be made clear to users that they are responsible for the security of their accounts.","checks_status": {"fail": 0,"pass": 0,"total": 22,"manual": 0}},"2.5.2": {"name": "User Identification","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.5.2 User Identification","Subdomain": "2.5. Authentication and Access Management","AuditEvidence": ["Login screen for information systems and personal information processing systems","Lists of administrators, users, and personal information handlers for information systems and personal information processing systems","Records of approvals for exceptions"],"AuditChecklist": ["Are unique identifiers assigned to users and personal information handlers in information systems and personal information processing systems, and is the use of easily guessable identifiers restricted?","If the same identifier is shared by multiple users for unavoidable reasons, has the justification been reviewed and have supplementary measures such as approval from the responsible party been established?"],"NonComplianceCases": ["Case 1: The account status of information systems (servers, networks, firewalls, DBMS, etc.) shows that default administrator accounts provided by the manufacturer are still in use, despite being technically modifiable.","Case 2: Developers are sharing personal information processing system accounts for common use without any justification or approval from responsible parties.","Case 3: External personnel maintaining information systems are using operational accounts like personal accounts without going through the required approval procedures."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "User accounts must be assigned unique identifiers that distinguish each user individually, and the use of easily guessable identifiers must be restricted. If the same identifier is shared by multiple users, the reason and justification must be reviewed, supplementary measures such as approval from a responsible party must be established, and accountability must be ensured.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.5.3": {"name": "User Authentication","checks": {"iam_root_mfa_enabled": null,"iam_user_accesskey_unused": null,"iam_check_saml_providers_sts": null,"cognito_user_pool_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_rotate_access_key_90_days": null,"iam_user_hardware_mfa_enabled": null,"iam_user_two_active_access_key": null,"iam_administrator_access_with_mfa": null,"iam_user_mfa_enabled_console_access": null,"iam_user_with_temporary_credentials": null,"apigatewayv2_api_authorizers_enabled": "FAIL","iam_user_no_setup_initial_access_key": null,"apigateway_restapi_authorizers_enabled": "PASS","rds_cluster_iam_authentication_enabled": "FAIL","rds_instance_iam_authentication_enabled": "FAIL","kafka_cluster_unrestricted_access_disabled": null,"cognito_identity_pool_guest_access_disabled": "FAIL","cognito_user_pool_advanced_security_enabled": null,"cognito_user_pool_self_registration_disabled": null,"directoryservice_supported_mfa_radius_enabled": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cognito_user_pool_client_token_revocation_enabled": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cognito_user_pool_client_prevent_user_existence_errors": null,"opensearch_service_domains_internal_user_database_enabled": null,"cognito_user_pool_blocks_potential_malicious_sign_in_attempts": null,"opensearch_service_domains_use_cognito_authentication_for_kibana": null,"cognito_user_pool_blocks_compromised_credentials_sign_in_attempts": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.5.3 User Authentication","Subdomain": "2.5. Authentication and Authorization Management","AuditEvidence": ["Login screen for information systems and personal information processing systems","Login attempt limitation setting screen","Login failure message screen","Procedures for external access (e.g., external access request forms, list of external accessors)"],"AuditChecklist": ["Is access to information systems and personal information processing systems controlled through secure user authentication procedures, login attempt limitations, and warnings for illegal login attempts?","When accessing personal information processing systems from outside via a communication network, are secure authentication methods or secure access measures applied in accordance with legal requirements?"],"NonComplianceCases": ["Case 1: When a personal information handler accesses a personal information processing system through the public external internet, secure authentication methods are not applied, and authentication is done only through ID and password.","Case 2: In the login process for information systems and personal information processing systems, detailed messages are displayed about whether the ID exists or the password is incorrect, and there is no limit on login failure attempts."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights), Article 6 (Access Control)"]}],"description": "User access to information systems, personal information, and critical information must be secured through safe authentication procedures and, if necessary, enhanced authentication methods. In addition, access control measures such as limiting login attempts and issuing warnings for illegal login attempts must be established and implemented.","checks_status": {"fail": 4,"pass": 1,"total": 29,"manual": 0}},"2.5.4": {"name": "Password Management","checks": {"iam_password_policy_number": null,"iam_password_policy_symbol": null,"iam_password_policy_reuse_24": null,"iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_password_policy_minimum_length_14": null,"cognito_user_pool_password_policy_number": null,"cognito_user_pool_password_policy_symbol": null,"cognito_user_pool_password_policy_lowercase": null,"cognito_user_pool_password_policy_uppercase": null,"cognito_user_pool_temporary_password_expiration": null,"cognito_user_pool_password_policy_minimum_length_14": null,"iam_password_policy_expires_passwords_within_90_days_or_less": null},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.5.4 Password Management","Subdomain": "2.5. Authentication and Authorization Management","AuditEvidence": ["Password setting screens for web pages, information systems, and personal information processing systems","Password management policies and procedures"],"AuditChecklist": ["Are procedures for managing and creating secure user passwords for information systems established and implemented?","Are password creation rules established and enforced to ensure that users can use secure passwords?","Are authentication methods for personal information handlers and users securely applied and managed?"],"NonComplianceCases": ["Case 1: Although password creation rules are set in policies and guidelines related to information protection and personal information protection, some information systems and personal information processing systems use passwords that differ from internal guidelines.","Case 2: Internal regulations state that when passwords are reset, temporary passwords must be assigned and forced to be changed, but in practice, temporary passwords are being used without change.","Case 3: Although internal regulations require users and personal information handlers to change their passwords periodically, passwords are being used without change."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "Procedures for managing passwords used by users of information systems, as well as customers and members, must be established and implemented, taking into account legal requirements and external threats.","checks_status": {"fail": 0,"pass": 0,"total": 13,"manual": 0}},"2.5.5": {"name": "Management of Special Accounts and Privileges","checks": {"iam_avoid_root_usage": null,"iam_root_mfa_enabled": null,"iam_no_root_access_key": null,"iam_support_role_created": null,"rds_cluster_default_admin": "FAIL","rds_instance_default_admin": "FAIL","ec2_instance_profile_attached": "PASS","iam_root_hardware_mfa_enabled": null,"organizations_delegated_administrators": null,"cloudwatch_log_metric_filter_root_usage": null,"sagemaker_notebook_instance_root_access_disabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.5.5 Management of Special Accounts and Privileges","Subdomain": "2.5. Authentication and Privilege Management","AuditEvidence": ["Guidelines related to special privileges","Records of special privilege requests and approvals","List of special privilege holders","Records of special privilege reviews"],"AuditChecklist": ["Is there a formal privilege request and approval process established and implemented to ensure that special privileges, such as administrative privileges, are only granted to a minimal number of people?","Is there a control procedure established and implemented to identify and manage accounts and privileges granted for special purposes in a separate list?"],"NonComplianceCases": ["Case 1: The approval history for granting administrator and special privileges in the information system and personal information processing system is not documented or does not match the special privileges list.","Case 2: Internal regulations require that personal information administrators and special privilege holders be documented and managed in a list, but the list is not maintained or some special privileges, such as security system administrators, are not identified or managed.","Case 3: A maintenance special account for visiting maintenance once a quarter remains active at all times without a time limit on usage.","Case 4: Regular reviews of administrator and special privilege usage are not conducted, and some individuals retain special privileges even after their roles have changed."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "Accounts and privileges used for special purposes, such as managing information systems, personal information, and important information, should be granted minimally, separately identified, and controlled.","checks_status": {"fail": 2,"pass": 1,"total": 11,"manual": 0}},"2.5.6": {"name": "Review of Access Rights","checks": {"accessanalyzer_enabled": "PASS","cloudtrail_insights_exist": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","accessanalyzer_enabled_without_findings": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"cloudwatch_cross_account_sharing_disabled": null,"cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_log_metric_filter_aws_organizations_changes": null,"cloudtrail_multi_region_enabled_logging_management_events": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.5.6 Review of Access Rights","Subdomain": "2.5. Authentication and Privilege Management","AuditEvidence": ["Access rights review standards and procedures","History of access rights reviews","Access rights review reports and follow-up action records"],"AuditChecklist": ["Are the histories of account and access right creation, registration, granting, use, modification, and deletion for information systems, personal information, and important information being recorded?","Are standards, review subjects, review methods, and periodic review schedules established to regularly review the appropriateness of user accounts and access rights to information systems, personal information, and important information?","When issues such as excessive access rights, failure to follow access right granting procedures, or misuse of access rights are identified in the review results, are appropriate response procedures established and implemented?"],"NonComplianceCases": ["Case 1: The methods, review periods, reporting structure, and misuse criteria related to access rights reviews are not clearly defined in the relevant guidelines, leading to irregular performance of access rights reviews.","Case 2: Although internal policies and guidelines require locking (deactivating) or deleting long-unused accounts, some accounts that have not been accessed for more than six months remain active (indicating that the access rights review was not thoroughly conducted, failing to identify these accounts).","Case 3: During the access rights review, cases of excessive privileges or suspected misuse were identified, but no detailed investigation, internal reporting, or follow-up actions were taken."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights)"]}],"description": "The registration, use, and deletion of user accounts accessing information systems, personal information, and important information, as well as the history of granting, changing, and deleting access rights, should be recorded and periodically reviewed to ensure their appropriateness.","checks_status": {"fail": 2,"pass": 1,"total": 14,"manual": 0}},"2.6.1": {"name": "Network Access","checks": {"ec2_ami_public": null,"elb_internet_facing": "FAIL","ec2_elastic_ip_shodan": null,"elbv2_internet_facing": "PASS","ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","kafka_cluster_is_public": null,"s3_bucket_acl_prohibited": "FAIL","apigateway_restapi_public": "FAIL","lightsail_database_public": null,"lightsail_instance_public": null,"ec2_securitygroup_not_used": "FAIL","elbv2_listeners_underneath": "PASS","networkfirewall_in_all_vpc": "FAIL","s3_bucket_public_write_acl": null,"ec2_instance_imdsv2_enabled": "PASS","rds_snapshots_public_access": "PASS","ssm_documents_set_as_public": "PASS","awslambda_function_url_public": null,"dms_instance_no_public_access": null,"rds_instance_no_public_access": "PASS","emr_cluster_publicly_accesible": null,"redshift_cluster_public_access": null,"neptune_cluster_public_snapshot": null,"eks_cluster_private_nodes_enabled": null,"awslambda_function_url_cors_policy": null,"documentdb_cluster_public_snapshot": null,"eks_cluster_network_policy_enabled": null,"neptune_cluster_uses_public_subnet": null,"sns_topics_not_publicly_accessible": "PASS","sqs_queues_not_publicly_accessible": "PASS","vpc_subnet_no_public_ip_by_default": "FAIL","vpc_subnet_separate_private_public": "FAIL","eks_cluster_not_publicly_accessible": null,"glacier_vaults_policy_public_access": null,"iam_user_mfa_enabled_console_access": null,"s3_access_point_public_access_block": "PASS","s3_bucket_level_public_access_block": "PASS","iam_user_administrator_access_policy": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"iam_group_administrator_access_policy": null,"s3_account_level_public_access_blocks": null,"apigateway_restapi_authorizers_enabled": "PASS","elasticache_cluster_uses_public_subnet": "PASS","rds_instance_iam_authentication_enabled": "FAIL","appstream_fleet_maximum_session_duration": null,"ec2_networkacl_allow_ingress_tcp_port_22": "FAIL","ecr_repositories_not_publicly_accessible": "PASS","emr_cluster_account_public_block_enabled": "PASS","sagemaker_models_vpc_settings_configured": null,"apigateway_restapi_public_with_authorizer": "FAIL","ec2_instance_port_ftp_exposed_to_internet": "PASS","ec2_instance_port_rdp_exposed_to_internet": "PASS","ec2_instance_port_ssh_exposed_to_internet": "PASS","vpc_endpoint_connections_trust_boundaries": "FAIL","appstream_fleet_session_disconnect_timeout": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_instance_port_cifs_exposed_to_internet": "PASS","ec2_instance_port_ldap_exposed_to_internet": "PASS","ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","kafka_cluster_unrestricted_access_disabled": null,"sagemaker_models_network_isolation_enabled": null,"cognito_identity_pool_guest_access_disabled": "FAIL","ec2_instance_port_kafka_exposed_to_internet": "PASS","ec2_instance_port_mysql_exposed_to_internet": "PASS","ec2_instance_port_redis_exposed_to_internet": "PASS","workspaces_vpc_2private_1public_subnets_nat": null,"ec2_instance_port_oracle_exposed_to_internet": "PASS","ec2_instance_port_telnet_exposed_to_internet": "PASS","ec2_instance_port_mongodb_exposed_to_internet": "PASS","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_instance_port_kerberos_exposed_to_internet": "PASS","ec2_transitgateway_auto_accept_vpc_attachments": null,"appstream_fleet_session_idle_disconnect_timeout": null,"ec2_instance_port_cassandra_exposed_to_internet": "PASS","ec2_instance_port_memcached_exposed_to_internet": "PASS","ec2_instance_port_sqlserver_exposed_to_internet": "PASS","rds_instance_event_subscription_security_groups": "FAIL","sagemaker_training_jobs_vpc_settings_configured": null,"vpc_peering_routing_tables_with_least_privilege": "PASS","appstream_fleet_default_internet_access_disabled": null,"ec2_instance_port_postgresql_exposed_to_internet": "PASS","ec2_securitygroup_with_many_ingress_egress_rules": "PASS","cloudfront_distributions_geo_restrictions_enabled": null,"sagemaker_training_jobs_network_isolation_enabled": null,"opensearch_service_domains_not_publicly_accessible": null,"sagemaker_notebook_instance_vpc_settings_configured": null,"cloudtrail_logs_s3_bucket_is_not_publicly_accessible": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_any_port": "PASS","vpc_endpoint_services_allowed_principals_trust_boundaries": null,"ec2_instance_port_elasticsearch_kibana_exposed_to_internet": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","cognito_user_pool_blocks_potential_malicious_sign_in_attempts": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Control Measures","Section": "2.6.1 Network Access","Subdomain": "2.6. Access Control","AuditEvidence": ["Network diagram","IP management ledger","Information asset list","Firewall rules"],"AuditChecklist": ["Has the organization identified all access paths to its network and ensured that internal networks are controlled so that only authorized users can access them according to the access control policy?","Has the organization physically or logically segmented the network based on services, user groups, information asset importance, and legal requirements, and applied access control between different network segments?","Has the organization established IP address allocation standards for each network segment, and applied measures such as assigning private IPs to systems like database servers that do not require external connections?","Has the organization implemented protective measures for communication paths when connecting networks between physically separated locations, such as IDCs, branches, and agents?"],"NonComplianceCases": ["Case 1: The network configuration and interviews revealed that data transmission and reception between external sites and the servers located in the IDC are being processed through the general internet line, rather than using VPN or dedicated lines as specified in internal regulations.","Case 2: The IP addresses of some important servers, such as database servers located in the internal network, were set to public IPs instead of private IPs as per internal regulations, and network access blocking was not applied.","Case 3: Although a server farm was established, access from the internal network to the server farm was excessively allowed due to insufficient network access control settings.","Case 4: The network provided to external parties (e.g., external developers, visitors) was not separated from the internal business network without appropriate controls.","Case 5: Contrary to internal regulations, the organization's network could be accessed and used simply by connecting a network cable without applying protective measures such as MAC address authentication and mandatory security software installation."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "In order to control unauthorized access to the network, management procedures such as IP management and device authentication must be established and implemented. Network segmentation (DMZ, server farm, DB zone, development zone, etc.) and access controls must be applied according to the business purpose and importance.","checks_status": {"fail": 17,"pass": 54,"total": 112,"manual": 0}},"2.6.2": {"name": "Access to Information Systems","checks": {"ec2_elastic_ip_shodan": null,"ec2_instance_public_ip": "FAIL","ec2_elastic_ip_unassigned": "FAIL","lightsail_instance_public": null,"lightsail_static_ip_unused": null,"ec2_instance_managed_by_ssm": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL","ec2_networkacl_allow_ingress_tcp_port_22": "FAIL","ec2_instance_port_ftp_exposed_to_internet": "PASS","ec2_instance_port_rdp_exposed_to_internet": "PASS","ec2_instance_port_ssh_exposed_to_internet": "PASS","ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_instance_port_telnet_exposed_to_internet": "PASS","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_securitygroup_with_many_ingress_egress_rules": "PASS","ec2_instance_internet_facing_with_instance_profile": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_any_port": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Protection Requirements","Section": "2.6.2 Access to Information Systems","Subdomain": "2.6. Access Control","AuditEvidence": ["List of operating system accounts of information systems","Server security settings","Server access control policy (e.g., SecureOS management screen)","Server and network configuration diagram","Information asset list"],"AuditChecklist": ["Have users, access locations, and access means allowed to access operating systems (OS) of information systems such as servers, network systems, and security systems been defined and controlled?","Is the system automatically disconnected when there is no work processed after accessing the information system for a certain period?","Are services unrelated to the purpose of using the information system removed?","Are information systems that provide key services operated on independent servers?"],"NonComplianceCases": ["Case 1: When a server administrator accesses a Windows server located in the IDC from the office using terminal services, session timeout settings are not configured, allowing the session to remain open for a long period without any activity.","Case 2: Due to improper restrictions on server-to-server access, a user authorized to access a particular server can access other unauthorized servers via that server.","Case 3: Unsafe access protocols (e.g., telnet, ftp) are being used without valid reasons or compensatory measures, and unnecessary services and ports are open.","Case 4: Although the access control policy requires all access to servers to go through a server access control system, bypass routes exist that allow access to servers without going through the system."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "The users, access restriction methods, and secure access means for accessing information systems such as servers and network systems must be defined and controlled.","checks_status": {"fail": 8,"pass": 13,"total": 24,"manual": 0}},"2.6.3": {"name": "Access to Applications","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Requirements","Section": "2.6.3 Access to Applications","Subdomain": "2.6. Access Control","AuditEvidence": ["Application access rights classification system","Application account and rights management screen","Application user and administrator screens (e.g., personal information viewing, etc.)","Application session time and concurrent session restriction settings","Application administrator access log monitoring details","Information asset list","Personal information processing system's personal information viewing and search screens","Personal information masking standards","Personal information masking application screen"],"AuditChecklist": ["Are access rights to applications granted differentially based on the user's tasks to control access to sensitive information?","Are sessions automatically disconnected after a certain period of inactivity, and is the number of simultaneous sessions per user restricted?","Is access to administrator-exclusive applications (e.g., admin web pages, admin consoles) restricted to unauthorized users?","Are criteria established and applied to ensure consistency in protection measures for limiting the display of personal and sensitive information?","Are applications implemented and operated to minimize unnecessary exposure (e.g., viewing, screen display, printing, downloading) of personal and sensitive information?"],"NonComplianceCases": ["Case 1: There is a flaw in the authorization control function of certain personal information processing screens in the application, allowing users without permission to view personal information.","Case 2: The administrator page of the application is open to the public internet without secure authentication methods applied.","Case 3: Session timeouts or concurrent logins for the same user account are not restricted without valid reasons.","Case 4: When personal information is downloaded through the application, the file contains excessive unnecessary information such as resident registration numbers.","Case 5: The application excessively allows 'like' searches, allowing all users to retrieve all customer information by searching only for a surname, even beyond their work scope.","Case 6: Due to the lack of criteria for limiting the display of personal information or failure to adhere to them, different masking standards are applied to the same personal information items on different screens of the personal information processing system.","Case 7: Although personal information is masked on the screen of the personal information processing system, unmasked personal information is exposed by viewing the web browser source."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights), Article 6 (Access Control), Article 12 (Safety Measures for Printing and Copying)"]}],"description": "Access rights to applications must be restricted according to the user's tasks and the importance of the accessed information, and criteria should be established to minimize exposure of unnecessary or sensitive information.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.6.4": {"name": "Database Access","checks": {"accessanalyzer_enabled": "PASS","lightsail_database_public": null,"rds_snapshots_public_access": "PASS","dms_instance_no_public_access": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"neptune_cluster_public_snapshot": null,"rds_instance_transport_encrypted": "FAIL","documentdb_cluster_public_snapshot": null,"neptune_cluster_uses_public_subnet": null,"vpc_subnet_separate_private_public": "FAIL","dynamodb_table_cross_account_access": null,"rds_cluster_iam_authentication_enabled": "FAIL","accessanalyzer_enabled_without_findings": "FAIL","rds_instance_iam_authentication_enabled": "FAIL","ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","neptune_cluster_iam_authentication_enabled": null,"ec2_instance_port_mysql_exposed_to_internet": "PASS","ec2_instance_port_redis_exposed_to_internet": "PASS","ec2_instance_port_oracle_exposed_to_internet": "PASS","ec2_instance_port_mongodb_exposed_to_internet": "PASS","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_instance_port_cassandra_exposed_to_internet": "PASS","ec2_instance_port_sqlserver_exposed_to_internet": "PASS","opensearch_service_domains_not_publicly_accessible": null,"opensearch_service_domains_https_communications_enforced": null,"opensearch_service_domains_internal_user_database_enabled": null,"ec2_instance_port_elasticsearch_kibana_exposed_to_internet": "PASS","opensearch_service_domains_use_cognito_authentication_for_kibana": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.6.4 Database Access","Subdomain": "2.6. Access Control","AuditEvidence": ["Database status (e.g., tables, columns)","List of database user accounts and permissions","Database access control policy (e.g., database access control system management screen)","Network diagram (e.g., database zone)","Information asset list"],"AuditChecklist": ["Are you identifying the information stored and managed in the database, such as the table list?","Are you clearly identifying the applications, information systems (servers), and users that need access to information in the database and controlling access according to the access control policy?"],"NonComplianceCases": ["Case 1: A database that stores and processes a large amount of personal information is operated on the same physical server as a web application accessible via the Internet, without separating them.","Case 2: Developers and operators share accounts used by the application to access the production database.","Case 3: Although internal regulations require database access rights to be restricted by object, access rights to the database are granted uniformly to administrators, even those who do not need access to personal information tables.","Case 4: A database access control solution has been implemented, but access to the database is not properly restricted by IP address, allowing users to bypass the access control solution.","Case 5: The table status of a database storing personal information has not been identified, resulting in the unnecessary retention of personal information in temporary tables that have not been deleted."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 5 (Management of Access Rights), Article 6 (Access Control)"]}],"description": "Identify the information stored and managed in the database, such as the table list, and establish and implement access control policies according to the importance of the information and the type of applications and users.","checks_status": {"fail": 6,"pass": 19,"total": 37,"manual": 0}},"2.6.5": {"name": "Wireless Network Access","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.6.5 Wireless Network Access","Subdomain": "2.6. Access Control","AuditEvidence": ["Network diagram","AP security settings history","Inspection records of unauthorized wireless networks","Wireless network usage application and approval records"],"AuditChecklist": ["When using a wireless network for business purposes, are you establishing and implementing protection measures such as authentication and encryption of transmitted and received data to ensure the security of the wireless AP and network segment?","Have you established and implemented procedures for applying for and terminating access to ensure that only authorized employees can use the wireless network?","Have you established and implemented protection measures against unauthorized wireless networks, such as detecting and blocking AD Hoc connections and unauthorized wireless APs within the organization?"],"NonComplianceCases": ["Case 1: The wireless network segments for external users and internal users are the same, allowing external users to access the internal network without separate control via the wireless network.","Case 2: Although the encryption function for information transmission and reception was enabled when configuring the wireless AP, it was set in an insecure manner.","Case 3: A wireless AP connected to the internal network for business purposes has security settings that are insufficient, such as exposure of the administrator password (using the default password) and lack of access control."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "When using a wireless network, wireless network protection measures such as user authentication, encryption of transmitted and received data, and AP control must be applied. In addition, protection measures must be established and implemented to prevent unauthorized wireless network access, such as AD Hoc connections and the use of unauthorized APs.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.6.6": {"name": "Remote Access Control","checks": {"vpc_flow_logs_enabled": "FAIL","networkfirewall_in_all_vpc": "FAIL","cognito_user_pool_mfa_enabled": null,"iam_user_console_access_unused": null,"vpc_subnet_no_public_ip_by_default": "FAIL","vpc_subnet_separate_private_public": "FAIL","iam_user_mfa_enabled_console_access": null,"workspaces_volume_encryption_enabled": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","appstream_fleet_maximum_session_duration": null,"ec2_networkacl_allow_ingress_tcp_port_22": "FAIL","ec2_instance_port_rdp_exposed_to_internet": "PASS","ec2_instance_port_ssh_exposed_to_internet": "PASS","appstream_fleet_session_disconnect_timeout": null,"ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","cognito_identity_pool_guest_access_disabled": "FAIL","workspaces_vpc_2private_1public_subnets_nat": null,"cognito_user_pool_self_registration_disabled": null,"appstream_fleet_session_idle_disconnect_timeout": null,"appstream_fleet_default_internet_access_disabled": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"ec2_client_vpn_endpoint_connection_logging_enabled": null,"cloudwatch_log_metric_filter_authentication_failures": null,"ec2_securitygroup_allow_ingress_from_internet_to_any_port": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.6.6 Remote Access Control","Subdomain": "2.6. Access Control","AuditEvidence": ["Remote access application form (e.g., VPN)","VPN account list","VPN access control policy settings","IP management log","Remote access control settings (server settings, security system settings, etc.)","Designation and management of management terminals","Network diagram"],"AuditChecklist": ["Is remote operation of information systems through external networks such as the internet prohibited in principle, and are compensatory measures in place if allowed for unavoidable reasons such as incident response?","Is access through remote operation of information systems allowed only for specific devices when done through internal networks?","Are protective measures established and implemented to prevent security incidents such as data breaches and hacking during remote work, such as telecommuting, remote collaboration, and smart work?","Are the devices used for remote access to personal information processing systems for management, operation, development, and security purposes designated as management terminals, and are safety measures such as prohibiting unauthorized operations and use for purposes other than those intended being applied?"],"NonComplianceCases": ["Case 1: Although internal regulations state that remote access to the system is prohibited in principle and, when allowed, access is restricted through IP-based access control, remote desktop connections and SSH access to the system are not limited by IP addresses, allowing access from any PC.","Case 2: A VPN has been established for remote management, but it is always available without usage approval or access period restrictions.","Case 3: Work-related mobile apps have been installed on personal smart devices for external workers, but appropriate protective measures (e.g., antivirus, encryption, wiping in case of loss or theft) to prevent personal information leaks are not being applied.","Case 4: VPN access for external users is not limited by network segments and information systems, allowing excessive access to the entire internal network and information systems for authenticated remote users."],"RelatedRegulations": ["Personal Information Protection Act Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information Article 6 (Access Control)"]}],"description": "Managing information systems and handling personal information outside of protected areas is, in principle, prohibited. However, if remote access is allowed for unavoidable reasons such as telecommuting, incident response, or remote collaboration, protective measures must be established and implemented, including approval from responsible personnel, designation of access devices, setting access scope and duration, enhanced authentication, encrypted communication, and securing access devices (e.g., antivirus, patches).","checks_status": {"fail": 8,"pass": 5,"total": 26,"manual": 0}},"2.6.7": {"name": "Internet Access Control","checks": {"ec2_elastic_ip_shodan": null,"vpc_flow_logs_enabled": "FAIL","ec2_instance_public_ip": "FAIL","ec2_elastic_ip_unassigned": "FAIL","networkfirewall_in_all_vpc": "FAIL","vpc_subnet_no_public_ip_by_default": "FAIL","vpc_subnet_separate_private_public": "FAIL","workspaces_volume_encryption_enabled": null,"route53_dangling_ip_subdomain_takeover": null,"appstream_fleet_maximum_session_duration": null,"appstream_fleet_session_disconnect_timeout": null,"cloudwatch_changes_to_vpcs_alarm_configured": null,"workspaces_vpc_2private_1public_subnets_nat": null,"ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","appstream_fleet_session_idle_disconnect_timeout": null,"appstream_fleet_default_internet_access_disabled": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.6.7 Internet Access Control","Subdomain": "2.6. Access Control","AuditEvidence": ["Policy for blocking non-work-related sites (e.g., P2P) (management screen of non-work-related site blocking system)","Internet access monitoring history","List of individuals subject to internet access restriction measures","Procedures and records for data transfer between networks (e.g., application and approval records)","Network diagram"],"AuditChecklist": ["Is there an established and implemented policy to control internet access for work PCs used for key duties and personal information handling terminals?","Is unnecessary external internet access from key information systems (e.g., database servers) being controlled?","Are internet access restrictions being applied in a secure manner for individuals who are required by law to have their internet access restricted?"],"NonComplianceCases": ["Case 1: Internet access restriction measures were applied according to the Personal Information Protection Act, but the restriction was not applied to some individuals with the authority to set access rights for personal information processing systems.","Case 2: Although internet access restriction measures were applied as required under the Personal Information Protection Act, it was possible to bypass the restriction by accessing the system through another server, allowing the download and deletion of personal information.","Case 3: Some servers located in the DMZ and internal network were unnecessarily able to access the internet directly.","Case 4: Although a physical network separation system was applied between internet PCs and internal work PCs, and a data transfer system was established, there was no approval process for data transfers, and there was no periodic review of the data transfer records.","Case 5: Internal regulations require that individuals handling personal information obtain approval from a responsible person before accessing P2P or web hard drive sites, and access is only permitted for a specific period, but there are numerous cases of exceptions being made without going through the approval process."],"RelatedRegulations": ["Personal Information Protection Act Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information Article 6 (Access Control)"]}],"description": "To prevent information leaks, malware infections, and intrusions into the internal network through the internet, policies must be established and implemented to restrict internet access or services (e.g., P2P, web hard drives, messengers) on key information systems, devices handling sensitive duties, and terminals processing personal information.","checks_status": {"fail": 6,"pass": 1,"total": 19,"manual": 0}},"2.7.1": {"name": "Application of Encryption Policy","checks": {"elb_ssl_listeners": "FAIL","backup_vaults_exist": null,"elbv2_ssl_listeners": "FAIL","ssm_document_secrets": "PASS","backup_vaults_encrypted": "PASS","rds_snapshots_encrypted": "FAIL","elb_insecure_ssl_ciphers": "PASS","s3_bucket_kms_encryption": "FAIL","ec2_ebs_volume_encryption": "PASS","ec2_ebs_default_encryption": "PASS","elbv2_insecure_ssl_ciphers": "PASS","athena_workgroup_encryption": null,"ec2_ebs_snapshots_encrypted": "FAIL","s3_bucket_default_encryption": "PASS","ec2_instance_secrets_user_data": "PASS","ec2_launch_template_no_secrets": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","rds_instance_transport_encrypted": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","neptune_cluster_storage_encrypted": null,"s3_bucket_secure_transport_policy": "FAIL","documentdb_cluster_storage_encrypted": null,"workspaces_volume_encryption_enabled": null,"awslambda_function_no_secrets_in_code": "PASS","glue_database_connections_ssl_enabled": null,"athena_workgroup_enforce_configuration": null,"cloudfront_distributions_https_enabled": null,"cloudwatch_log_group_no_secrets_in_logs": "FAIL","cloudformation_stack_outputs_find_secrets": "PASS","codebuild_project_no_secrets_in_variables": "PASS","kafka_cluster_encryption_at_rest_uses_cmk": null,"sns_subscription_not_using_http_endpoints": "PASS","sns_topics_kms_encryption_at_rest_enabled": "FAIL","sqs_queues_server_side_encryption_enabled": "PASS","awslambda_function_no_secrets_in_variables": "PASS","dynamodb_tables_kms_cmk_encryption_enabled": null,"glue_etl_jobs_amazon_s3_encryption_enabled": "PASS","acm_certificates_with_secure_key_algorithms": "PASS","cloudwatch_log_group_kms_encryption_enabled": "FAIL","ecs_task_definitions_no_environment_secrets": "PASS","kafka_cluster_in_transit_encryption_enabled": null,"storagegateway_fileshare_encryption_enabled": null,"apigateway_restapi_client_certificate_enabled": "FAIL","glue_etl_jobs_job_bookmark_encryption_enabled": "FAIL","glue_data_catalogs_metadata_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"dynamodb_accelerator_cluster_encryption_enabled": null,"kafka_cluster_mutual_tls_authentication_enabled": null,"directoryservice_radius_server_security_protocol": null,"glue_development_endpoints_s3_encryption_enabled": null,"glue_etl_jobs_cloudwatch_logs_encryption_enabled": "FAIL","autoscaling_find_secrets_ec2_launch_configuration": "PASS","eks_cluster_kms_cmk_encryption_in_secrets_enabled": null,"elasticache_redis_cluster_rest_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null,"cloudfront_distributions_field_level_encryption_enabled": null,"cloudfront_distributions_using_deprecated_ssl_protocols": null,"elasticache_redis_cluster_in_transit_encryption_enabled": null,"opensearch_service_domains_https_communications_enforced": null,"sagemaker_training_jobs_intercontainer_encryption_enabled": null,"glue_data_catalogs_connection_passwords_encryption_enabled": "FAIL","glue_development_endpoints_job_bookmark_encryption_enabled": null,"opensearch_service_domains_node_to_node_encryption_enabled": null,"sagemaker_training_jobs_volume_and_output_encryption_enabled": null,"glue_development_endpoints_cloudwatch_logs_encryption_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.7.1 Application of Encryption Policy","Subdomain": "2.7. Application of Encryption","AuditEvidence": ["Encryption control policy (targets, methods, algorithms, etc.)","Encryption application status (during storage and transmission)","Risk analysis results (if encryption is not applied to unique identifiers other than resident registration numbers in the internal network)","Encryption solution management screen"],"AuditChecklist": ["Has an encryption policy been established that includes encryption targets, encryption strength, and encryption usage in consideration of legal requirements for the protection of personal and important information?","Is encryption applied to personal and important information during storage, transmission, and transfer according to the encryption policy?"],"NonComplianceCases": ["Case 1: Internal policies and guidelines do not properly specify encryption targets, encryption strength, encryption methods during storage and transmission, or the roles and responsibilities of those responsible for encryption, considering legal requirements.","Case 2: The company applied incorrect regulations during the creation of its encryption policy, leading to non-compliance with legal encryption requirements (e.g., storing user account numbers without encryption).","Case 3: Although one-way encryption was applied to the passwords of both personal information handlers and data subjects, an insecure MD5 algorithm was used.","Case 4: Although a security server was applied to an internet shopping mall in accordance with relevant laws and internal regulations, encryption was missing in some sections where users' personal information is transmitted (e.g., viewing or modifying member information, password retrieval, password changes).","Case 5: Passwords for accessing information systems, authentication keys, and other values were stored in plaintext in system configuration files and source code."],"RelatedRegulations": ["Personal Information Protection Act, Article 24-2 (Restrictions on Processing of Resident Registration Numbers), Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 7 (Encryption of Personal Information)"]}],"description": "To protect personal and important information, encryption policies that reflect legal requirements, such as encryption targets, encryption strength, and encryption usage policies, must be established. Encryption must be applied during the storage, transmission, and transfer of personal and important information.","checks_status": {"fail": 18,"pass": 19,"total": 66,"manual": 0}},"2.7.2": {"name": "Cryptographic Key Management","checks": {"kms_cmk_are_used": null,"kms_cmk_rotation_enabled": null,"kms_key_not_publicly_accessible": null,"kms_cmk_not_deleted_unintentionally": null,"rds_instance_certificate_expiration": "PASS","secretsmanager_automatic_rotation_enabled": "FAIL","acm_certificates_transparency_logs_enabled": "PASS","directoryservice_ldap_certificate_expiration": null,"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null},"status": "FAIL","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.7.2 Cryptographic Key Management","Subdomain": "2.7. Application of Encryption","AuditEvidence": ["Cryptographic Key Management Policy","Cryptographic Key Management Log and System Screens"],"AuditChecklist": ["Are procedures for the generation, use, storage, distribution, modification, recovery, and destruction of cryptographic keys established and implemented?","Are cryptographic keys securely stored in a separate location to ensure they can be recovered if necessary, and is access to the use of cryptographic keys minimized?"],"NonComplianceCases": ["Case 1: If encryption policies do not specify procedures and methods for managing cryptographic keys, leading to varying levels and methods of cryptographic key management among personnel, resulting in vulnerabilities.","Case 2: Internal regulations require the generation of encryption keys under the approval of a responsible person when encrypting important information, and to maintain a key management log, but some keys are either missing or outdated in the log.","Case 3: The encryption key applied in the development system is the same as the one applied in the production system, making it easy to decrypt actual data through the development system."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 7 (Encryption of Personal Information)"]}],"description": "Establish and implement management procedures for the secure generation, use, storage, distribution, and destruction of cryptographic keys, and prepare recovery methods if necessary.","checks_status": {"fail": 1,"pass": 2,"total": 9,"manual": 0}},"2.8.1": {"name": "Definition of Security Requirements","checks": {"macie_is_enabled": "PASS","securityhub_enabled": "PASS","fms_policy_compliant": null,"guardduty_is_enabled": "PASS","inspector2_is_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","accessanalyzer_enabled": "PASS","networkfirewall_in_all_vpc": "FAIL","guardduty_centrally_managed": "FAIL","wafv2_webacl_logging_enabled": "FAIL","config_recorder_all_regions_enabled": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","codebuild_project_no_secrets_in_variables": "PASS","codebuild_project_user_controlled_buildspec": "PASS","wellarchitected_workload_no_high_or_medium_risks": "FAIL","codebuild_project_source_repo_url_no_sensitive_credentials": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.8.1 Definition of Security Requirements","Subdomain": "2.8. Security for Information System Introduction and Development","AuditEvidence": ["Information System Acquisition Standards and Procedures","RFP (Request for Proposal) and Purchase Contracts for Information System Introduction","Development Outputs (Project Execution Plans, Requirements Definition, Screen Design, Security Architecture Design, Test Plans, etc.)","Secure Coding Standards"],"AuditChecklist": ["When introducing, developing, or modifying an information system, are procedures for reviewing the validity of information protection and personal information protection aspects and for acquisition established and implemented?","When introducing, developing, or modifying an information system, are security requirements, including legal requirements and the latest vulnerabilities, clearly defined and reflected from the design stage?","Are coding standards for secure implementation of the information system established and applied?"],"NonComplianceCases": ["Case 1: Lack of established security verification standards and procedures prior to acquiring an information system.","Case 2: Internal regulations require the review of the security impact and the operating environment when introducing a new system, but recent acquisitions of some information systems lacked detailed standards and plans, and therefore, no security review was conducted during the acquisition.","Case 3: Internal development guidelines do not define key security requirements related to development (authentication and encryption, security logging, etc.).","Case 4: In the 'Development Standards Definition Document', user passwords are to be encrypted using insecure algorithms (MD5, SHA1), resulting in failure to comply with relevant legal requirements."],"RelatedRegulations": []}],"description": "When introducing, developing, or modifying information systems, security requirements such as legal requirements related to information protection and personal information protection, the latest security vulnerabilities, and secure coding methods must be defined and applied.","checks_status": {"fail": 7,"pass": 7,"total": 16,"manual": 0}},"2.8.2": {"name": "Review and Testing of Security Requirements","checks": {"macie_is_enabled": "PASS","securityhub_enabled": "PASS","fms_policy_compliant": null,"guardduty_is_enabled": "PASS","inspector2_is_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","accessanalyzer_enabled": "PASS","networkfirewall_in_all_vpc": "FAIL","guardduty_centrally_managed": "FAIL","wafv2_webacl_logging_enabled": "FAIL","inspector2_active_findings_exist": "FAIL","config_recorder_all_regions_enabled": null,"guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","accessanalyzer_enabled_without_findings": "FAIL","codebuild_project_no_secrets_in_variables": "PASS","codebuild_project_user_controlled_buildspec": "PASS","wellarchitected_workload_no_high_or_medium_risks": "FAIL","codebuild_project_source_repo_url_no_sensitive_credentials": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.8.2 Review and Testing of Security Requirements","Subdomain": "2.8. Security for Information System Introduction and Development","AuditEvidence": ["Information System Acceptance Test Results","Requirements Traceability Matrix","Test Plans, Test Results","Vulnerability Assessment Results","Personal Information Impact Assessment Report","Confirmation of Implementation of Corrective Actions for Personal Information Impact Assessment"],"AuditChecklist": ["When introducing, developing, or modifying an information system, are tests conducted to verify whether the security requirements defined during the analysis and design stages have been effectively applied?","Are vulnerability assessments conducted to confirm that the information system has been securely developed according to secure coding standards?","Are procedures established and implemented to ensure that issues identified during testing and vulnerability assessments are promptly addressed through corrective action plans and follow-up checks?","For public institutions, are impact assessments conducted during the analysis and design stages when developing or modifying personal information processing systems, as required by relevant laws, and are the results reflected during development and modification?"],"NonComplianceCases": ["Case 1: Failure to test security requirements defined in internal guidelines and documents after implementing an information system.","Case 2: In the application program test scenario and technical vulnerability checklist, important validation items such as input validation checks were omitted.","Case 3: Failure to assess whether known technical vulnerabilities exist during implementation or testing, or failure to address identified vulnerabilities without valid reasons or approval.","Case 4: A public institution failed to conduct an impact assessment when developing a personal information file or personal information processing system subject to an impact assessment requirement, such as processing unique identifiers of more than 50,000 data subjects.","Case 5: A public institution failed to submit the impact assessment report to the Personal Information Protection Commission within two months after receiving the report from the impact assessment agency.","Case 6: Internal guidelines require reviewing the security and impact on the operating environment when introducing a new system (e.g., vulnerability assessments), but recent acquisitions of some information systems lacked security reviews during the acceptance process."],"RelatedRegulations": ["Personal Information Protection Act, Article 33 (Personal Information Impact Assessment)","Notification on Personal Information Impact Assessment"]}],"description": "To verify that an information system has been introduced or implemented according to predefined security requirements, review standards and procedures must be established and implemented to check compliance with legal requirements, the latest security vulnerabilities, secure coding implementation, and personal information impact assessment, and corrective measures must be taken for any identified issues.","checks_status": {"fail": 10,"pass": 7,"total": 19,"manual": 0}},"2.8.3": {"name": "Separation of Test and Production Environments","checks": {"codebuild_project_user_controlled_buildspec": "PASS"},"status": "PASS","attributes": [{"Domain": "2. Security Requirements for Protection Measures","Section": "2.8.3 Separation of Test and Production Environments","Subdomain": "2.8. Security for Information System Introduction and Development","AuditEvidence": ["Network diagrams (including test environment configuration)","Current application of access control between the production environment and the development/test environment"],"AuditChecklist": ["Are development and test systems separated from the production system?","If separation of development and production environments is difficult due to unavoidable reasons, have security measures such as mutual review, monitoring by supervisors, approval for changes, and ensuring accountability been implemented?"],"NonComplianceCases": ["Case 1: Source code changes are being made directly in the production environment without a separate development environment or proper approval.","Case 2: Although it is unavoidable to operate the development and production systems without separation, records of mutual review or monitoring are missing.","Case 3: Although a separate development system is in place, access from the development environment to the production environment is not controlled, allowing developers unnecessary access to the production system through the development system."],"RelatedRegulations": []}],"description": "Development and test systems must, in principle, be separated from production systems to reduce the risk of unauthorized access and changes to the production system.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"2.8.4": {"name": "Test Data Security","checks": {"codebuild_project_no_secrets_in_variables": "PASS"},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.8.4 Test Data Security","Subdomain": "2.8. Security in Information System Introduction and Development","AuditEvidence": ["Test data status","Test data generation rules","If operational data was used in a test environment, the approval history"],"AuditChecklist": ["Is the use of actual operational data restricted during the development and testing of information systems?","If it is inevitable to use operational data in a test environment, are control procedures such as approval by the responsible person, monitoring of access and leakage, and deletion of data after testing established and implemented?"],"NonComplianceCases": ["Case 1: There are no specific standards and procedures established for generating test data for use on the development server.","Case 2: Operational data is being used as test data without proper processing and without approval from the responsible person for a valid reason.","Case 3: Although operational data was approved in advance for use as test data for unavoidable reasons, the same level of access control as the operational database is not applied to the test database.","Case 4: After using operational data for testing purposes, the data was not deleted from the test database even though the testing was completed."],"RelatedRegulations": []}],"description": "In order to prevent the leakage of operational data during system testing, procedures for the creation, use, management, disposal, and technical protection measures of test data must be established and implemented.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"2.8.5": {"name": "Source Program Management","checks": {"ecr_repositories_not_publicly_accessible": "PASS","codeartifact_packages_external_public_publishing_disabled": null},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.8.5 Source Program Management","Subdomain": "2.8. Security in Information System Introduction and Development","AuditEvidence": ["Status of configuration management systems such as SVN (e.g., list of authorized personnel)","History of changes to the source program"],"AuditChecklist": ["Have procedures been established and implemented to control access to source programs by unauthorized persons?","Is the source program stored safely in a non-operational environment for emergencies such as system failures?","Is the history of changes to the source program being managed?"],"NonComplianceCases": ["Case 1: There is no separate backup or configuration management system for source programs, and previous versions of the source code are stored on the operational server or developer's PC without approval or history management.","Case 2: A configuration management system has been established, but access control, access and change history for the system or the source code stored in the system are not properly managed.","Case 3: The internal regulations require version control of source programs through a configuration management system, but the latest version of the source program is only stored on the developer's PC, and no separate backup is performed."],"RelatedRegulations": []}],"description": "Source programs must be managed so that only authorized users can access them, and it is a principle that they should not be stored in the operational environment.","checks_status": {"fail": 0,"pass": 1,"total": 2,"manual": 0}},"2.8.6": {"name": "Transition to Operational Environment","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.8.6 Transition to Operational Environment","Subdomain": "2.8. Security in Information System Introduction and Development","AuditEvidence": ["Transition procedures","Transition records (requests, approvals, tests, transitions, etc.)"],"AuditChecklist": ["Have control procedures been established and implemented to safely transition newly introduced, developed, or modified systems to the operational environment?","Are contingency plans in place to address issues that may arise during the transition to the operational environment?","Are only the files necessary for service execution installed in the operational environment?"],"NonComplianceCases": ["Case 1: There are no procedures in place to review and approve the transition of developed or modified source programs to the operational environment.","Case 2: Unnecessary files (source code, distribution modules, backups, development-related documents, manuals, etc.) exist in the operational server.","Case 3: The internal guidelines require the preparation of change request and result documents for safe transition and recovery during transitions to the operational environment, but such documents are not available.","Case 4: The internal guidelines require internal review and approval before distributing mobile apps to the app market, but developers are bypassing these procedures and distributing the apps directly."],"RelatedRegulations": []}],"description": "When transitioning newly introduced, developed, or modified systems to the operational environment, the process must be controlled, and the executable code must be run according to test and user acceptance procedures.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.9.1": {"name": "Change Management","checks": {"codebuild_project_older_90_days": "FAIL","config_recorder_all_regions_enabled": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_aws_organizations_changes": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.9.1 Change Management","Subdomain": "2.9. System and Service Operations Management","AuditEvidence": ["Change management procedures","Change management records (requests, approvals, change details, etc.)","Impact analysis results of changes"],"AuditChecklist": ["Have procedures been established and implemented for changes to assets related to information systems (hardware, operating systems, commercial software packages, etc.)?","Are the performance and security impacts analyzed before making changes to information system-related assets?"],"NonComplianceCases": ["Case 1: A recent change to the DMZ section for redundancy was made, but there is no evidence of performing and approving the security risk and performance evaluation that may occur after the change.","Case 2: A recent network change was made, but the review and notification were not sufficiently carried out, so the changes were not properly reflected in the network diagram or some access control systems (e.g., firewalls, database access control systems) ACLs.","Case 3: Although a change management system was established to analyze and discuss the impact on performance and security when information systems are introduced or changed, changes can still be made outside the system, and related changes are not properly reviewed."],"RelatedRegulations": []}],"description": "Procedures must be established and implemented to manage all changes to assets related to information systems, and the impact on system performance and security must be analyzed before changes are made.","checks_status": {"fail": 2,"pass": 0,"total": 14,"manual": 0}},"2.9.2": {"name": "Performance and Fault Management","checks": {"rds_cluster_multi_az": "FAIL","elb_is_in_multiple_az": "FAIL","rds_instance_multi_az": "FAIL","elbv2_is_in_multiple_az": "PASS","s3_bucket_no_mfa_delete": "FAIL","vpc_subnet_different_az": "PASS","neptune_cluster_multi_az": null,"elbv2_deletion_protection": "FAIL","autoscaling_group_multiple_az": null,"dms_instance_multi_az_enabled": null,"rds_cluster_backtrack_enabled": null,"cloudtrail_multi_region_enabled": "PASS","rds_cluster_deletion_protection": "FAIL","rds_instance_deletion_protection": "FAIL","acm_certificates_expiration_check": "PASS","s3_bucket_cross_region_replication": "FAIL","trustedadvisor_errors_and_warnings": null,"config_recorder_all_regions_enabled": null,"kms_cmk_not_deleted_unintentionally": null,"neptune_cluster_deletion_protection": null,"networkfirewall_deletion_protection": null,"rds_instance_certificate_expiration": "PASS","route53_domains_transferlock_enabled": null,"cloudtrail_bucket_requires_mfa_delete": null,"elb_cross_zone_load_balancing_enabled": "PASS","documentdb_cluster_deletion_protection": null,"documentdb_cluster_cloudwatch_log_export": null,"ec2_instance_detailed_monitoring_enabled": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL","iam_no_expired_server_certificates_stored": null,"kafka_cluster_enhanced_monitoring_enabled": null,"elasticache_redis_cluster_multi_az_enabled": null,"directoryservice_ldap_certificate_expiration": null,"cognito_user_pool_deletion_protection_enabled": null,"trustedadvisor_premium_support_plan_subscribed": null,"directoryservice_directory_monitor_notifications": null,"cloudformation_stacks_termination_protection_enabled": "FAIL","cloudtrail_multi_region_enabled_logging_management_events": null,"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.9.2 Performance and Fault Management","Subdomain": "2.9. System and Service Operations Management","AuditEvidence": ["Procedures for performance and capacity monitoring","Evidence of performance and capacity monitoring (e.g., internal reporting results)","Fault response procedures","Fault response report"],"AuditChecklist": ["Have procedures been established and implemented to continuously monitor performance and capacity to ensure the availability of information systems?","Are response procedures in place and implemented to address cases where the performance and capacity requirements (thresholds) of the information system are exceeded?","Have procedures been established and implemented to immediately recognize and respond to information system faults?","Are procedures in place to record and manage actions taken in response to faults through fault response reports?","For serious faults, are measures being taken to prevent recurrence through cause analysis?"],"NonComplianceCases": ["Case 1: Failure to define requirements (e.g., thresholds) for managing performance and capacity for each target, or the absence of records in regular inspection reports, making it difficult to assess the current status.","Case 2: Performance or capacity standards were exceeded, but no related reviews or follow-up measures were taken or implemented.","Case 3: Fault response procedures for IT equipment have been established, but internal and external environmental changes such as network configuration or vendor changes are not adequately reflected.","Case 4: Inconsistencies exist between fault handling procedures and fault type-specific response methods, or there is a lack of rationale for estimating response times, making swift, accurate, and systematic responses difficult."],"RelatedRegulations": []}],"description": "To ensure the availability of information systems, performance and capacity requirements must be defined, and the status must be continuously monitored. Procedures for detecting, recording, analyzing, recovering, and reporting in response to faults must be established and managed effectively.","checks_status": {"fail": 11,"pass": 6,"total": 39,"manual": 0}},"2.9.3": {"name": "Backup and Recovery Management","checks": {"ec2_ami_public": null,"backup_plans_exist": "PASS","backup_vaults_exist": null,"backup_vaults_encrypted": "PASS","ec2_ebs_public_snapshot": "PASS","efs_have_backup_enabled": "FAIL","s3_bucket_public_access": null,"backup_reportplans_exist": null,"s3_bucket_kms_encryption": "FAIL","s3_bucket_public_list_acl": null,"s3_bucket_public_write_acl": null,"ec2_ebs_snapshots_encrypted": "FAIL","rds_instance_backup_enabled": "PASS","rds_snapshots_public_access": "PASS","s3_bucket_lifecycle_enabled": "FAIL","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"s3_bucket_default_encryption": "PASS","rds_cluster_backtrack_enabled": null,"neptune_cluster_backup_enabled": null,"ec2_ebs_volume_snapshots_exists": "FAIL","neptune_cluster_public_snapshot": null,"documentdb_cluster_backup_enabled": null,"documentdb_cluster_public_snapshot": null,"rds_cluster_copy_tags_to_snapshots": "FAIL","s3_bucket_cross_region_replication": "FAIL","rds_instance_copy_tags_to_snapshots": null,"redshift_cluster_automated_snapshot": null,"s3_access_point_public_access_block": "PASS","s3_bucket_policy_public_write_access": "PASS","lightsail_instance_automated_snapshots": null,"dlm_ebs_snapshot_lifecycle_policy_exists": "FAIL","elasticache_redis_cluster_backup_enabled": null,"ecr_repositories_lifecycle_policy_enabled": "FAIL","directoryservice_directory_snapshots_limit": null,"ec2_ebs_snapshot_account_block_public_access": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.9.3 Backup and Recovery Management","Subdomain": "2.9. System and Service Operation Management","AuditEvidence": ["Backup and recovery procedures","Recovery test results","Disaster recovery backup status"],"AuditChecklist": ["Have backup and recovery procedures been established and implemented, including targets, frequency, methods, and procedures?","Is regular recovery testing conducted to verify the completeness and accuracy of the backed-up information and the adequacy of the recovery procedures?","For backup media containing critical information, is the media stored in physically separate locations to address disaster recovery?"],"NonComplianceCases": ["Case 1: Backup and recovery procedures, including targets, frequency, methods, and procedures, have not been established.","Case 2: Although a backup policy is in place, information required to be stored for a long period (6 months, 3 years, 5 years, etc.) according to legal requirements is not being stored according to the backup policy.","Case 3: Some systems (e.g., security system policies and logs) that are required to be separately backed up according to higher-level or internal guidelines are not being backed up.","Case 4: Although higher-level or internal guidelines stipulate that recovery tests for backup media should be conducted periodically, recovery tests have not been performed for an extended period."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 11 (Safety Measures for Disaster Recovery)"]}],"description": "To maintain the availability and data integrity of the information system, procedures must be established and implemented regarding the backup targets, frequency, methods, storage locations, retention periods, and disaster recovery. Additionally, management must ensure timely recovery in case of incidents.","checks_status": {"fail": 11,"pass": 8,"total": 37,"manual": 0}},"2.9.4": {"name": "Log and Access Record Management","checks": {"macie_is_enabled": "PASS","elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","inspector2_is_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","ec2_ebs_public_snapshot": "PASS","eventbridge_bus_exposed": "PASS","rds_snapshots_encrypted": "FAIL","s3_bucket_public_access": null,"s3_bucket_kms_encryption": "FAIL","cloudtrail_insights_exist": null,"s3_bucket_public_list_acl": null,"s3_bucket_public_write_acl": null,"ec2_ebs_snapshots_encrypted": "FAIL","ec2_instance_managed_by_ssm": "FAIL","efs_not_publicly_accessible": "FAIL","guardduty_centrally_managed": "FAIL","rds_snapshots_public_access": "PASS","s3_bucket_default_encryption": "PASS","wafv2_webacl_logging_enabled": "FAIL","iam_securityaudit_role_created": null,"redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","config_recorder_all_regions_enabled": null,"s3_access_point_public_access_block": "PASS","s3_bucket_level_public_access_block": "PASS","eventbridge_bus_cross_account_access": "FAIL","s3_bucket_policy_public_write_access": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"s3_account_level_public_access_blocks": null,"cloudtrail_log_file_validation_enabled": "FAIL","cloudtrail_s3_dataevents_write_enabled": null,"apigatewayv2_api_access_logging_enabled": "FAIL","cloudwatch_log_group_no_secrets_in_logs": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"s3_bucket_server_access_logging_enabled": "FAIL","cloudfront_distributions_logging_enabled": null,"documentdb_cluster_cloudwatch_log_export": null,"ec2_instance_detailed_monitoring_enabled": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","cloudwatch_cross_account_sharing_disabled": null,"kafka_cluster_enhanced_monitoring_enabled": null,"acm_certificates_transparency_logs_enabled": "PASS","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","cloudwatch_log_metric_filter_policy_changes": null,"eks_control_plane_logging_all_types_enabled": null,"ec2_ebs_snapshot_account_block_public_access": null,"iam_inline_policy_no_full_access_to_cloudtrail": null,"trustedadvisor_premium_support_plan_subscribed": null,"cloudtrail_logs_s3_bucket_access_logging_enabled": "FAIL","cloudwatch_log_metric_filter_sign_in_without_mfa": null,"directoryservice_directory_monitor_notifications": null,"eventbridge_schema_registry_cross_account_access": "FAIL","glue_etl_jobs_cloudwatch_logs_encryption_enabled": "FAIL","opensearch_service_domains_audit_logging_enabled": null,"directoryservice_directory_log_forwarding_enabled": null,"ec2_client_vpn_endpoint_connection_logging_enabled": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudtrail_logs_s3_bucket_is_not_publicly_accessible": "PASS","cloudwatch_log_metric_filter_authentication_failures": null,"opensearch_service_domains_cloudwatch_logging_enabled": null,"cloudwatch_log_metric_filter_aws_organizations_changes": null,"route53_public_hosted_zones_cloudwatch_logging_enabled": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudtrail_multi_region_enabled_logging_management_events": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL","glue_development_endpoints_cloudwatch_logs_encryption_enabled": null,"awslambda_function_invoke_api_operations_cloudtrail_logging_enabled": "PASS","cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.9.4 Log and Access Record Management","Subdomain": "2.9. System and Service Operation Management","AuditEvidence": ["Log management procedures","Log record details","Access control records for log storage devices","Access records of personal information"],"AuditChecklist": ["Has the organization established log management procedures for information systems such as servers, applications, security systems, and network systems, and is it generating and storing the necessary logs accordingly?","Are log records of information systems securely stored to prevent tampering, theft, or loss, and is access to the log records minimized?","Are access records for personal information processing systems securely stored for a specified period in accordance with legal requirements, including all necessary items?"],"NonComplianceCases": ["Case 1: The detailed criteria and procedures for log recording, retention periods, review frequency, and responsible personnel have not been established.","Case 2: The maximum size for critical logs such as security event logs, application, and service logs (for Windows Server 2008 or later) is not sufficiently configured, resulting in logs not being recorded and retained for the period specified by internal standards.","Case 3: The log records of important Linux/UNIX servers are not separately backed up or adequately protected, allowing users to arbitrarily delete command execution histories and access logs.","Case 4: Upon reviewing access records for the personal information processing system, while the account, access time, and IP address of the user were logged, details about the data subject information handled and the tasks performed (e.g., view, modify, delete, download) were not recorded.","Case 5: The capacity of the log server is insufficient, leaving only two months of access records for the personal information processing system.","Case 6: A personal information processing system handling personal information of 100,000 data subjects is only retaining access logs for one year."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 8 (Retention and Inspection of Access Records)"]}],"description": "The organization must define the types of logs, retention periods, and retention methods for user access records, system logs, and privilege grant records for information systems such as servers, applications, security systems, and network systems, and must securely retain and manage them to prevent tampering, theft, or loss.","checks_status": {"fail": 25,"pass": 15,"total": 81,"manual": 0}},"2.9.5": {"name": "Log and Access Record Inspection","checks": {"cloudtrail_insights_exist": null,"inspector2_active_findings_exist": "FAIL","trustedadvisor_errors_and_warnings": null,"guardduty_no_high_severity_findings": "FAIL","accessanalyzer_enabled_without_findings": "FAIL","cloudtrail_threat_detection_enumeration": null,"cloudwatch_log_group_no_secrets_in_logs": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"cloudwatch_cross_account_sharing_disabled": null,"cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_log_metric_filter_aws_organizations_changes": null,"cognito_user_pool_client_prevent_user_existence_errors": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL","cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Control Requirements","Section": "2.9.5 Log and Access Record Inspection","Subdomain": "2.9. System and Service Operation Management","AuditEvidence": ["Log review and monitoring procedures","Log review and monitoring results (review details, reports, etc.)","Access record inspection details for personal information","Criteria and results for verifying reasons for personal information downloads","Evidence of responses to detected anomalies"],"AuditChecklist": ["Are there established log review and monitoring procedures, including the frequency, targets, and methods for detecting errors, misuse (unauthorized access, excessive queries, etc.), fraud, and other anomalies in the information system?","Are the results of log reviews and monitoring reported to the responsible person, and are responses taken following procedures when anomalies are detected?","Are access records of the personal information processing system regularly inspected according to the periods specified in relevant laws?"],"NonComplianceCases": ["Case 1: Monitoring and alert policies (criteria) for abnormal access (e.g., early morning access on holidays, access via bypass routes) or abnormal behaviors (e.g., large-scale data queries or continuous small data queries) on information systems processing important information have not been established.","Case 2: Although periodic inspection/monitoring criteria for access and usage are established in internal guidelines or systems, there is no record of actual review of abnormal access or behavior.","Case 3: The personal information processor sets the inspection frequency of access records for personal information processing systems to once per quarter.","Case 4: The internal management plan for the personal information processor sets criteria for verifying reasons when more than 1,000 items of personal information are downloaded, but the reasons are not verified when such downloads occur."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 8 (Retention and Inspection of Access Records)"]}],"description": "To ensure normal use of the information system and prevent misuse (unauthorized access, excessive queries, etc.) by users, log review criteria for access and usage must be established and inspected periodically, and post-event actions must be taken promptly if issues arise.","checks_status": {"fail": 6,"pass": 0,"total": 26,"manual": 0}},"2.9.6": {"name": "Time Synchronization","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Control Requirements","Section": "2.9.6 Time Synchronization","Subdomain": "2.9. System and Service Operation Management","AuditEvidence": ["Time synchronization settings","Evidence of time synchronization for key systems"],"AuditChecklist": ["Is the system time synchronized with the standard time?","Is regular inspection conducted to ensure that time synchronization is functioning properly?"],"NonComplianceCases": ["Case 1: The time of some critical systems (e.g., security systems, CCTV, etc.) is not synchronized with the standard time, and regular inspections for synchronization are not being conducted.","Case 2: Although internal NTP servers are configured for time synchronization, some systems are not synchronized, and there has been no cause analysis or response."],"RelatedRegulations": []}],"description": "To ensure the accuracy of logs and access records and provide reliable log analysis, the system time must be synchronized with a standard time and regularly maintained.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.9.7": {"name": "Reuse and Disposal of Information Assets","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Control Requirements","Section": "2.9.7 Reuse and Disposal of Information Assets","Subdomain": "2.9. System and Service Operation Management","AuditEvidence": ["Procedures for the disposal and reuse of information assets","Storage media management ledger","Evidence of the disposal of information assets and storage media","Disposal-related outsourcing contracts for information assets and storage media"],"AuditChecklist": ["Are secure reuse and disposal procedures for information assets established and implemented?","When reusing or disposing of information assets and storage media, are personal and critical information processed to be irrecoverable?","If information assets and storage media are disposed of internally, are the disposal records maintained in a management ledger along with evidence of disposal?","If disposal is outsourced to an external company, are disposal procedures specified in the contract and is the complete disposal confirmed?","Are measures in place to protect data on storage media during maintenance, repairs, or replacements of systems and PCs?"],"NonComplianceCases": ["Case 1: Although the policy and procedure require the complete deletion of data using a data deletion program when reusing PCs used by personal information handlers, in practice, PCs are reused without complete deletion or are only formatted before reuse, indicating that procedures are not being followed.","Case 2: Although storage media are disposed of through an external company, the contract lacks details on secure disposal procedures and protective measures, and there is no verification or supervision of the disposal process or evidence of compliance.","Case 3: Instead of recording the serial numbers of disposed HDDs, the system names are recorded, or the disposal ledger is not maintained, making it impossible to verify the disposal history and traceability.","Case 4: Discarded hard disks are left unsecured in an area without locks, and the data has not been fully deleted."],"RelatedRegulations": ["Personal Information Protection Act, Article 21 (Destruction of Personal Information)","Standards for Ensuring the Safety of Personal Information, Article 13 (Destruction of Personal Information)"]}],"description": "To prevent the recovery or regeneration of personal and critical information during the reuse and disposal process, secure reuse and disposal procedures for information assets must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.1": {"name": "Collection and Use of Personal Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.1.1 Collection and Use of Personal Information","Subdomain": "3.1. Protection Measures during Personal Information Collection","AuditEvidence": ["Online personal information collection forms (e.g., website sign-up screens, mobile app registration screens, event participation forms)","Offline personal information collection forms (e.g., membership application forms)","Records of personal information collection consent (e.g., member databases)","Records of legal guardian consent","Privacy policy"],"AuditChecklist": ["When collecting personal information, is it collected in accordance with lawful requirements such as obtaining the data subjectās consent, complying with legal obligations, or concluding and fulfilling contracts?","When obtaining consent from the data subject for the collection of personal information, are the method and timing of obtaining consent appropriate?","When obtaining consent from the data subject for the collection of personal information, are the relevant details clearly communicated, and are significant points required by law highlighted in a way that is easy to understand?","When collecting, using, or providing personal information from children under the age of 14, are necessary details notified to their legal representatives, and is consent obtained?","When obtaining the consent of a legal representative, is only the minimum necessary personal information collected, and are procedures and methods in place to verify the qualifications of the legal representative?","When notifying children under the age of 14 about matters related to the processing of their personal information, are the notifications presented in a format and language that is clear and easy to understand?","Are records of consent obtained from data subjects and legal representatives being retained?","For personal information that can be processed without the consent of the data subject, are the relevant items and legal basis for processing disclosed in the privacy policy or communicated to the data subject separately from the personal information processed with consent?","When personal information is used for additional purposes without the consent of the data subject, are criteria established and implemented to assess the relevance to the original purpose, predictability, impact on the data subject, and safety measures? If additional usage continues to occur, are these criteria disclosed in the privacy policy and regularly reviewed?"],"NonComplianceCases": ["Case 1: A personal information processor subject to the Personal Information Protection Act failed to include the 'right to refuse consent and the consequences of refusal' in the notifications when obtaining consent to collect personal information.","Case 2: During the process of obtaining consent for the collection of personal information, the items of personal information to be collected were not specified in detail, and were instead described in general terms like 'etc.'","Case 3: On a shopping mall website, personal information necessary for membership registration was collected alongside payment and delivery information required for future purchases, even though such information was not necessary at the time of registration.","Case 4: Personal information (e.g., name, email, phone number) was collected through Q&A boards without obtaining the data subject's consent.","Case 5: Personal information of children under the age of 14 was collected without obtaining the consent of their legal guardians.","Case 6: Although the service was not intended for children under 14, some members were under 14 because the website did not check birthdates during registration, allowing them to register without legal guardian consent.","Case 7: The procedure for verifying the authenticity of the legal representative was insufficient, allowing individuals who were not legal guardians to provide consent.","Case 8: Personal information (e.g., name, phone number) of legal guardians was collected for the purpose of obtaining their consent to collect personal information from children under the age of 14, but the consent of the legal guardian was not confirmed for an extended period, and the information was retained without being destroyed.","Case 9: Personal information of children under 14 was collected based on the consent of their legal guardians, but records of this consent were not maintained, making it impossible to verify the details related to legal guardian consent (e.g., legal guardianās name, time of consent)."],"RelatedRegulations": ["Personal Information Protection Act, Article 15 (Collection and Use of Personal Information), Article 22 (Methods for Obtaining Consent), Article 22-2 (Protection of Personal Information of Children)","Notice on the Processing of Personal Information"]}],"description": "Personal information must be collected and used lawfully and fairly. When collecting personal information based on the consent of the data subject, such consent must be obtained through legal means. Additionally, when collecting personal information from children under the age of 14, consent must be obtained from their legal representative, and it must be verified that such consent was given by the legal representative.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.2": {"name": "Restrictions on the Collection of Personal Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.1.2 Restrictions on the Collection of Personal Information","Subdomain": "3.1. Protection Measures during Personal Information Collection","AuditEvidence": ["Online personal information collection forms (e.g., website sign-up screens, event participation forms)","Offline personal information collection forms (e.g., membership application forms)","Privacy policy"],"AuditChecklist": ["When collecting personal information, is only the minimum amount of information necessary for the intended purpose being collected?","When collecting personal information based on the data subjectās consent, is the data subject clearly informed that they can refuse to consent to the collection of additional personal information beyond the minimum required?","Is the data subject not denied goods or services for refusing to consent to the collection of additional personal information beyond the minimum necessary for the intended purpose?"],"NonComplianceCases": ["Case 1: Although personal information was being collected based on the fulfillment of a contract, excessive personal information not essential to the fulfillment of the contract was being collected.","Case 2: During the process of obtaining consent from the data subject for optional information, the data subject was not explicitly informed that they could refuse to provide such information.","Case 3: Although the sign-up form distinguished between required and optional information, the data subject was not clearly informed that they could complete registration without providing optional information (e.g., there was no indication on the personal information entry form of which fields were required and which were optional).","Case 4: On the website registration page, the data subject was unable to proceed or complete registration if they refused to provide optional information or consent to optional matters.","Case 5: During the hiring process, excessive personal information unrelated to the job position (e.g., family details) was collected."],"RelatedRegulations": ["Personal Information Protection Act, Article 16 (Restrictions on the Collection of Personal Information), Article 22 (Methods for Obtaining Consent)"]}],"description": "When collecting personal information, only the minimum amount of personal information necessary for the intended purpose may be collected, and the data subject must not be denied the provision of goods or services for refusing to consent to optional matters.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.3": {"name": "Restrictions on the Processing of Resident Registration Numbers","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.1.3 Restrictions on the Processing of Resident Registration Numbers","Subdomain": "3.1. Protection Measures during Personal Information Collection","AuditEvidence": ["Personal information collection forms (e.g., website sign-up screens, event participation forms, membership application forms)","Online personal information collection forms (alternative registration methods for identity verification)","Evidence of legal grounds for processing resident registration numbers","Privacy policy"],"AuditChecklist": ["Are resident registration numbers only processed when there is a clear legal basis?","Is the legal provision that forms the basis for the collection of resident registration numbers clearly identified?","When processing resident registration numbers under a legal basis, does the organization provide a method for data subjects to register without using their resident registration number during the membership registration process on an internet website?"],"NonComplianceCases": ["Case 1: Resident registration numbers were collected for simple membership management purposes, such as identity verification, during website sign-up based on the data subject's consent.","Case 2: Resident registration numbers were collected based on provisions in enforcement rules or local ordinances.","Case 3: The last 6 digits of the resident registration number were collected for identity verification, such as during password recovery, without any legal basis.","Case 4: Resident registration numbers were collected from job applicants during the hiring process without a legal basis.","Case 5: Resident registration numbers were collected during customer service inquiries at a call center for identity verification purposes.","Case 6: Even when there was a legal basis for the collection of resident registration numbers, alternative registration methods were not provided during the membership registration process on the website, and resident registration numbers were required for identity verification and membership registration."],"RelatedRegulations": ["Personal Information Protection Act, Article 24-2 (Restrictions on the Processing of Resident Registration Numbers)","Information and Communications Network Act, Article 23-2 (Restrictions on the Use of Resident Registration Numbers)"]}],"description": "Resident registration numbers may not be collected, used, or processed unless there is a legal basis for doing so. Even when the processing of resident registration numbers is permitted, alternative methods must be provided, such as through an internet website.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.4": {"name": "Restriction on Processing of Sensitive and Unique Identifying Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Personal Information Processing Requirements","Section": "3.1.4 Restriction on Processing of Sensitive and Unique Identifying Information","Subdomain": "3.1. Protection Measures for Personal Information Collection","AuditEvidence": ["Online personal information collection forms (e.g., membership sign-up pages, event participation forms)","Offline personal information collection forms (e.g., membership application forms)","Privacy policy"],"AuditChecklist": ["Is sensitive information processed only with the separate consent of the data subject or when legally required?","Is unique identifying information (excluding resident registration numbers) processed only with the separate consent of the data subject or when there is a specific legal basis?","If there is a risk of invasion of privacy due to the disclosure of sensitive information during the provision of goods or services, is the data subject clearly informed of the possibility of such disclosure and how to opt for non-disclosure before the provision of goods or services?"],"NonComplianceCases": ["Case 1: Collecting sensitive information such as disability status for discounts or benefits for disabled individuals, and obtaining blanket consent for all personal information items.","Case 2: Collecting foreign registration numbers only from foreigners during membership registration, and obtaining blanket consent for all personal information items.","Case 3: When obtaining separate consent for the collection of sensitive or unique identifying information, failing to inform or incorrectly informing the data subject about the four key points that must be disclosed (e.g., the right to refuse consent and the consequences of refusal)."],"RelatedRegulations": ["Personal Information Protection Act, Article 23 (Restrictions on Processing of Sensitive Information), Article 24 (Restrictions on Processing of Unique Identifying Information)"]}],"description": "In order to process sensitive information and unique identifying information (excluding resident registration numbers), separate consent from the data subject must be obtained unless the processing is specifically required or permitted by law.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.5": {"name": "Indirect Collection of Personal Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Personal Information Processing Requirements","Section": "3.1.5 Indirect Collection of Personal Information","Subdomain": "3.1. Protection Measures for Personal Information Collection","AuditEvidence": ["Contracts related to the provision of personal information (agreements with providers)","Records of notifications to data subjects about the source of personal information","Privacy policy"],"AuditChecklist": ["When receiving personal information from a third party, is it clearly stated in the contract that the responsibility for obtaining consent for the collection of personal information lies with the party providing the information?","When collecting personal information from public media or places, is the collection limited to the scope recognized as having the data subject's consent, based on common societal standards?","Even for personal information collected or generated through automated collection devices during the process of providing services, is the principle of minimum collection applied?","When personal information is collected from a source other than the data subject and the data subject requests it, is the required information immediately provided to the data subject?","When personal information collected from a source other than the data subject meets legal requirements in terms of type or scale, is the required information provided to the data subject?","Is there a record of informing the data subject about the source of personal information, and is this record maintained until the personal information is destroyed?"],"NonComplianceCases": ["Case 1: In the case of collecting personal information published on websites or social media, there is no procedure for handling requests from data subjects about the source of the information.","Case 2: Personal information provided by another business entity was received based on consent for the provision of personal information under Article 17(1)(1) of the Personal Information Protection Act, but the data subjects were not notified within three months (note: this applies to cases where the recipient handles the personal information of more than 50,000 data subjects, sensitive information, or unique identifying information, or processes personal information of over 1 million data subjects).","Case 3: The data subject was informed about the source of the personal information as required by law, but some mandatory notification items were omitted, such as the purpose of processing or the right to withdraw consent.","Case 4: The data subject was informed about the source of the personal information, but the record of this notification was not maintained until the personal information was destroyed, in violation of legal obligations."],"RelatedRegulations": ["Personal Information Protection Act, Article 16 (Restrictions on the Collection of Personal Information), Article 19 (Restrictions on Use and Provision of Personal Information Provided by a Third Party), Article 20 (Notification of the Source, Purpose, etc. of Indirectly Collected Personal Information)"]}],"description": "When collecting personal information from sources other than the data subject or when receiving personal information from a third party, only the minimum amount of personal information necessary for the task should be collected or received. If there is a legal basis or at the request of the data subject, the source of the personal information, the purpose of processing, and the right to request a suspension of processing must be disclosed.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.6": {"name": "Installation and Operation of Video Information Processing Devices","checks": {},"status": "PASS","attributes": [{"Domain": "3. Personal Information Processing Requirements","Section": "3.1.6 Installation and Operation of Video Information Processing Devices","Subdomain": "3.1. Protection Measures for Personal Information Collection","AuditEvidence": ["Status of video information processing device operation","Signs for video information processing devices","Video information processing device operation and management policies","Management screens for video information processing devices (e.g., account/permission details, video retention periods)","Contracts with operators of video information processing devices and inspection records"],"AuditChecklist": ["When installing and operating fixed video information processing devices in public places, is it reviewed whether the installation meets legal requirements?","If public institutions install and operate fixed video information processing devices in public places, are public hearings or explanation sessions held to gather opinions from relevant experts and stakeholders, as required by law?","When installing and operating fixed video information processing devices, are necessary measures taken, such as installing signs to ensure the data subject can easily recognize the presence of the devices?","When operating mobile video information processing devices in public places for business purposes, is it reviewed whether the operation meets legal requirements?","When operating mobile video information processing devices in public places for business purposes, is the fact that the video is being recorded indicated and informed to the public through lights, sounds, or signs?","Is there an operation and management policy in place for the safe management of video information processing devices and the video information they record, and is it being implemented?","Is the retention period for video information set, and is the information destroyed without delay after the retention period expires?","When outsourcing the operation of video information processing devices, are the related procedures and requirements reflected in the contract?"],"NonComplianceCases": ["Case 1: The wording on the signs for video information processing devices is incomplete, or there is no established and implemented policy for the operation and management of video information processing devices.","Case 2: Although there is a policy for the operation and management of video information processing devices, the policy is not followed, such as failing to comply with the retention period or failing to implement access control and logging as described in the policy.","Case 3: The operation of video information processing devices is outsourced, but the legal requirements, such as inspection of the video information management status and provisions regarding liability for damages, are not reflected in the contract.","Case 4: The operation of video information processing devices is outsourced, but the signs for the devices do not include the name and contact information of the contractor."],"RelatedRegulations": ["Personal Information Protection Act, Article 25 (Restrictions on the Installation and Operation of Fixed Video Information Processing Devices), Article 25-2 (Restrictions on the Operation of Mobile Video Information Processing Devices)"]}],"description": "When installing and operating fixed video information processing devices in public places or operating mobile video information processing devices in public places for business purposes, legal requirements must be followed according to the purpose and location of the installation, and appropriate protection measures must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.1.7": {"name": "Collection and Use of Personal Information for Marketing Purposes","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.1.7 Collection and Use of Personal Information for Marketing Purposes","Subdomain": "3.1. Protection Measures When Collecting Personal Information","AuditEvidence": ["Online personal information collection forms (e.g., website membership sign-up, mobile app sign-up, event participation)","Offline personal information collection forms (e.g., membership application forms)","Marketing consent records","Records of consent for receiving advertising information and confirmation of consent","Administrator screen for advertising information transmission systems (e.g., email, SMS, app push notifications)","Advertising information transmission content","Personal information processing policy"],"AuditChecklist": ["When obtaining consent from data subjects to process personal information for the purpose of promoting or recommending goods or services, is the data subject clearly informed, and is separate consent obtained?","When sending advertising information for profit using electronic transmission media, is the recipient's explicit prior consent obtained, and is the consent reconfirmed every two years?","When a recipient indicates refusal or withdraws prior consent for receiving advertising information for profit, is the transmission of such advertising information stopped?","When sending advertising information for profit, is the sender's name, method for opting out, etc., clearly stated, and are such messages not sent during nighttime hours?"],"NonComplianceCases": ["Case 1: When collecting personal information for 'promotion and marketing' purposes, the purpose is vaguely explained (e.g., 'providing additional services', 'providing partner services') or blanket consent is obtained without distinguishing between different purposes.","Case 2: Even after a user has expressed refusal to receive advertising push notifications via a mobile app, such notifications are sent due to a program error.","Case 3: The option to receive advertising information via text messages or email is pre-selected by default on the online sign-up page.","Case 4: The recipient's consent for receiving advertising information is not reconfirmed every two years.","Case 5: When sending advertising information for profit via email, the subject line does not begin with '(Advertisement)'."],"RelatedRegulations": ["Personal Information Protection Act, Article 22 (Method of Obtaining Consent)","Information and Communications Network Act, Article 50 (Restrictions on Transmission of Advertising Information)"]}],"description": "When collecting and using personal information for marketing purposes, such as promoting goods or services, sales recommendations, or sending advertising information, the purpose must be clearly communicated to the data subject, and their consent must be obtained.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.2.1": {"name": "Management of Personal Information Status","checks": {"macie_is_enabled": "PASS","s3_bucket_lifecycle_enabled": "FAIL"},"status": "FAIL","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.2.1 Management of Personal Information Status","Subdomain": "3.2. Protection Measures When Retaining and Using Personal Information","AuditEvidence": ["Personal information status table","Personal information flowchart","Registration status of personal information files","Personal information file management ledger","Personal information processing policy-related personal information files","Personal information files related to investigations under the Punishment of Tax Offenses Act and the Customs Act","Personal information files for one-time operations deemed to have a low need for continuous management as determined by Presidential Decree","Personal information files for simple tasks such as attending meetings, sending documents or materials, and financial settlements, which have a low need for continuous management","Personal information files processed temporarily for public health or public safety emergencies","Other personal information files collected for one-time tasks that are not stored or recorded","Personal information files classified as confidential under other laws","Personal information files collected or requested for analysis related to national security","Personal video information files processed via video information processing devices","Personal information files retained by financial institutions for handling financial transactions under the Real Name Financial Transactions and Guarantee of Secrecy Act"],"AuditChecklist": ["Is the status of collected and retained personal information, including the items, volume, purpose and method of processing, and retention period, regularly managed?","When a public institution operates or modifies personal information files, are the relevant matters registered with the head of the relevant agency as required by law?","Does the public institution disclose the status of personal information files in the personal information processing policy?"],"NonComplianceCases": ["Case 1: Although personal information files are managed through the website's personal information file registration menu, some personal information files related to website services are missing from the personal information processing policy.","Case 2: Although two months have passed since a new personal information file was created, it has not been registered with the Personal Information Protection Commission.","Case 3: The content of personal information files registered and disclosed with the Personal Information Protection Commission (e.g., items of personal information collected) does not match the actual status of personal information files being processed.","Case 4: A public institution has not registered personal information files with the Personal Information Protection Commission, even though the files do not qualify for exceptions such as employee personal information files or personal information files collected under the Statistics Act."],"RelatedRegulations": ["Personal Information Protection Act, Article 32 (Registration and Disclosure of Personal Information Files)"]}],"description": "The items, volume, purpose and method of processing, and retention period of collected and retained personal information must be regularly managed. In the case of public institutions, such information must be registered with the head of the relevant agency as stipulated by law.","checks_status": {"fail": 1,"pass": 1,"total": 2,"manual": 0}},"3.2.2": {"name": "Personal Information Quality Assurance","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.2.2 Personal Information Quality Assurance","Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information","AuditEvidence": ["Form for data subjects to modify/update their personal information (online, offline)","Procedures to maintain the up-to-date status of personal information"],"AuditChecklist": ["Are procedures and methods in place to maintain personal information in an accurate and up-to-date state?","Is there a method provided for data subjects to ensure the accuracy, completeness, and up-to-dateness of their personal information?"],"NonComplianceCases": ["Case 1: Although an identity verification process is implemented when changing member information through the website, the identity verification process is insufficient when changing member information via customer service, making unauthorized changes possible.","Case 2: While an online method is provided for online members to change their personal information, no such method is provided for offline members."],"RelatedRegulations": ["Personal Information Protection Act, Article 3 (Principles of Personal Information Protection)"]}],"description": "Collected personal information must be managed to ensure its accuracy, completeness, and up-to-dateness within the scope necessary for the processing purpose, and procedures must be provided to data subjects to manage their information.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.2.3": {"name": "Protection of User Device Access","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.2.3 Protection of User Device Access","Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information","AuditEvidence": ["App access rights consent screen","App access rights settings"],"AuditChecklist": ["When accessing information stored on the user's mobile device or functions installed on the device, are users clearly informed and their consent obtained?","Is it ensured that services are not denied if users do not consent to access rights that are not essential for the service?","Are methods provided for users to consent to or withdraw access rights on their mobile devices?"],"NonComplianceCases": ["Case 1: A smartphone app requests excessive access to personal information areas such as contacts, photos, and messages, even though such access is unnecessary for the service.","Case 2: A service provider's smartphone app accesses information stored on the smartphone and installed functions without notifying the user and obtaining their consent.","Case 3: Consent is obtained for app access rights by informing users that optional permissions are required as essential permissions.","Case 4: A smartphone app supports Android versions below 6.0, where individual consent for access rights is not possible, making it impossible for users to reject optional access rights."],"RelatedRegulations": ["Information and Communications Network Act, Article 22-2 (Consent for Access Rights)"]}],"description": "When accessing information stored on the user's mobile device or functions installed on the mobile device, it is necessary to notify the user clearly and obtain their consent.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.2.4": {"name": "Use and Provision of Personal Information Beyond Purpose","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.2.4 Use and Provision of Personal Information Beyond Purpose","Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information","AuditEvidence": ["Records of personal information use and provision beyond the original purpose (including related evidence such as requests)","Log of personal information use and provision beyond the original purpose (for public institutions)","Records of publication in the official gazette or on the website (for public institutions)","Guidelines for handling information provision requests","Official documents requesting information provision and records of personal information provision"],"AuditChecklist": ["Is personal information used or provided only within the scope of the purpose consented to by the data subject at the time of collection or as permitted by law?","When receiving personal information from a personal information processor, is the information used or provided only within the scope of the purpose for which it was provided?","If personal information is used or provided beyond the scope of the purpose of collection or the purpose for which it was received from a personal information processor, is additional consent obtained from the data subject or limited to cases with a legal basis?","When providing personal information to a third party for purposes beyond the original purpose, is the recipient required to take necessary actions to restrict the use of personal information and ensure safety?","When public institutions use or provide personal information beyond the original purpose, are the legal basis, purpose, and scope published in the official gazette or on the internet?","When public institutions use or provide personal information beyond the original purpose, is there a record of such use or provision and are procedures in place for managing it?"],"NonComplianceCases": ["Case 1: Personal information collected for product delivery is used for telemarketing of other company products without prior consent.","Case 2: Personal information collected for customer satisfaction surveys or sweepstakes entries is used for advertising other promotional events without consent.","Case 3: A public institution provides personal information to another institution for purposes outside the scope of the original purpose based on legal grounds but does not publish the information in the official gazette or on the internet.","Case 4: A public institution provides personal information to a police department for criminal investigation purposes but fails to record the details in the log of personal information use and provision beyond the original purpose."],"RelatedRegulations": ["Personal Information Protection Act, Article 18 (Restriction on the Use and Provision of Personal Information Beyond the Original Purpose), Article 19 (Restriction on Use and Provision by Recipients of Personal Information)"]}],"description": "Personal information must only be used or provided within the scope notified and consented to by the data subject at the time of collection or as permitted by law. If personal information is to be used or provided beyond this scope, additional consent must be obtained from the data subject or the legality must be verified, and appropriate protective measures must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.2.5": {"name": "Processing of Pseudonymized Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.2.5 Processing of Pseudonymized Information","Subdomain": "3.2. Protection Measures for Retention and Use of Personal Information","AuditEvidence": ["Procedures and results of the adequacy review of pseudonymization/anonymization","Records of pseudonymized information processing","Privacy policy (regarding the use and provision of pseudonymized information)"],"AuditChecklist": ["When processing pseudonymized information, are procedures established for purpose limitation, pseudonymization methods and standards, adequacy review, prohibition of re-identification, and actions in case of re-identification?","When using or providing pseudonymized personal information, is the information pseudonymized to a level where individuals cannot be identified without using or combining additional information?","When combining pseudonymized information with that of other personal information processors, is the combination conducted through a specialized agency or data professional organization?","When processing pseudonymized information, are technical, administrative, and physical measures taken to ensure safety, such as deleting or separately storing additional information and keeping records?","Is the processing period for pseudonymized information set to an appropriate period considering the processing purpose, and is the information destroyed without delay when that period expires?","When anonymizing personal information, is the information anonymized to a level where individuals cannot be identified even with the use of additional information, considering the time, cost, and technology available?"],"NonComplianceCases": ["Case 1: When processing pseudonymized information for statistical purposes or scientific research without obtaining consent from data subjects, records of the pseudonymization process were not kept, or the privacy policy was not updated to include relevant information.","Case 2: Additional information was not stored separately from pseudonymized information in the same database, or access rights to both sets of information were not appropriately segregated.","Case 3: Although pseudonymized personal information was used, the pseudonymization process was not sufficient, making it possible to identify individuals by combining the information with other data without using additional information.","Case 4: Personal information was anonymized for generating test data or for public release, but due to outliers or other factors, it was still possible to identify individuals, indicating that the anonymization process was not sufficient."],"RelatedRegulations": ["Personal Information Protection Act, Article 2 (Definitions), Article 28-2 (Processing of Pseudonymized Information), Article 28-3 (Restrictions on Combining Pseudonymized Information), Article 28-4 (Obligations for the Safe Processing of Pseudonymized Information), Article 28-5 (Prohibition of Re-identification in Processing Pseudonymized Information), Article 28-7 (Scope of Application), Article 58-2 (Exemptions)"]}],"description": "When processing pseudonymized information, legal requirements such as purpose limitation, combination restrictions, safety measures, and prohibition obligations must be met, and procedures must be established and implemented to ensure an appropriate level of pseudonymization.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.3.1": {"name": "Provision of Personal Information to Third Parties","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.3.1 Provision of Personal Information to Third Parties","Subdomain": "3.3. Protective Measures When Providing Personal Information","AuditEvidence": ["Forms related to the provision of personal information to third parties online (e.g., membership registration page, consent for third-party provision on websites)","Forms related to the provision of personal information to third parties offline (e.g., membership application forms, consent forms for third-party provision)","Records of third-party provisions","Privacy policy"],"AuditChecklist": ["When providing personal information to third parties, are legal requirements such as consent from the data subject or compliance with legal obligations clearly identified and followed?","When obtaining consent from the data subject for the provision of personal information to third parties, are the related matters clearly communicated, and is consent legally obtained by distinguishing it from other consents?","When obtaining consent from the data subject for the provision of personal information to third parties, are important matters clearly indicated and made easily understandable as required by law?","When providing personal information to third parties, is the information limited to the minimum necessary for the intended purpose?","When providing personal information to third parties, is it done through secure procedures and methods, and is the provision recorded and stored?","When allowing third parties to access personal information, is control implemented in accordance with protection procedures to securely protect the personal information?","When providing additional personal information without the data subject's consent, are criteria for determining the relevance to the original purpose of collection, predictability, potential harm, and safety measures established and followed? If such provisions continue, are these criteria disclosed in the privacy policy and periodically reviewed?"],"NonComplianceCases": ["Case 1: When obtaining consent from the data subject for the provision of personal information to third parties, some necessary information (e.g., the right to refuse consent, the items provided) was omitted.","Case 2: In the process of providing personal information to third parties, personal information from data subjects who did not consent was provided due to improper verification of consent.","Case 3: When obtaining consent for the provision of personal information, the recipient was not specifically identified and was vaguely referred to as Ź»~ etc.ʼ in the consent.","Case 4: Although third-party provision consent was optional during the membership registration process, if the data subject did not agree to third-party provision, the registration process could not be completed.","Case 5: An excessive amount of personal information was provided beyond what was necessary for the recipient's purpose of use."],"RelatedRegulations": ["Personal Information Protection Act, Article 17 (Provision of Personal Information), Article 22 (Methods of Obtaining Consent)","Notification on the Methods of Processing Personal Information"]}],"description": "When providing personal information to third parties, there must be a legal basis or consent from the data subject, and protection measures must be established and implemented to securely protect personal information during the process of providing access to third parties.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.3.2": {"name": "Outsourcing of Personal Information Processing","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.3.2 Outsourcing of Personal Information Processing","Subdomain": "3.3. Protective Measures When Providing Personal Information","AuditEvidence": ["Privacy policy (disclosing details related to the outsourcing of personal information processing)","Personal information collection forms","Contracts for outsourcing personal information processing","Records of notifications to data subjects regarding outsourced tasks related to promoting or selling goods or services"],"AuditChecklist": ["When outsourcing personal information processing tasks (including sub-outsourcing) to third parties, are the details of the outsourced tasks and the trustees regularly updated and disclosed on the website?","When outsourcing tasks related to promoting or selling goods or services, is the data subject notified of the details of the outsourced tasks and the trustees through methods such as written notice, email, or text messages?"],"NonComplianceCases": ["Case 1: Although the details of the outsourcing of personal information processing tasks were disclosed on the website's privacy policy, some trustees and the details of the outsourced tasks were missing.","Case 2: When outsourcing tasks related to promoting or selling goods or services, the details of the outsourced tasks and trustees were not notified to the data subject through written methods, and instead, the information was disclosed only in the privacy policy.","Case 3: After terminating a contract with an existing trustee for personal information processing, the new trustee was not promptly reflected in the privacy policy.","Case 4: Although the trustee sub-outsourced the personal information processing tasks to a third party, the sub-outsourcing details were not disclosed on the website."],"RelatedRegulations": ["Personal Information Protection Act, Article 26 (Restrictions on the Processing of Personal Information by Outsourcing)"]}],"description": "When outsourcing personal information processing tasks to third parties, the details of the outsourced tasks and the trustee must be disclosed. Additionally, if the task involves promoting or selling goods or services, the details of the outsourced task and the trustee must be notified to the data subject.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.3.3": {"name": "Transfer of Personal Information Due to Business Transfers","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.3.3 Transfer of Personal Information Due to Business Transfers","Subdomain": "3.3. Protective Measures When Providing Personal Information","AuditEvidence": ["Records of notifications to data subjects regarding the transfer of personal information (during business transfers)","Privacy policy"],"AuditChecklist": ["When transferring personal information to another party due to the transfer or merger of all or part of the business, are the necessary matters communicated to the data subjects in advance?","When receiving personal information, does the recipient notify the data subjects without delay regarding the fact that personal information has been received and other necessary matters, if legally required?","Does the recipient of the personal information use the information only for its original purpose at the time of transfer, or provide it to third parties in compliance with the original purpose?"],"NonComplianceCases": ["Case 1: When receiving personal information through business acquisition, the data subjects were not notified of the transfer of personal information, even though the data provider failed to notify them of the transfer.","Case 2: When receiving personal information through business acquisition or merger, no procedures or methods were provided to allow data subjects to opt-out of the transfer, nor were such options communicated to the data subjects."],"RelatedRegulations": ["Personal Information Protection Act, Article 27 (Restrictions on the Transfer of Personal Information Due to Business Transfers)"]}],"description": "When transferring or receiving personal information due to business transfers or mergers, appropriate protection measures such as notifying the data subjects must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.3.4": {"name": "Transfer of Personal Information Abroad","checks": {"s3_bucket_cross_region_replication": "FAIL"},"status": "FAIL","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.3.4 Transfer of Personal Information Abroad","Subdomain": "3.3. Protection Measures When Providing Personal Information","AuditEvidence": ["Consent form for personal information transfer abroad","Contract related to personal information transfer abroad","Privacy policy","Notification or disclosure records regarding outsourcing or storage of personal information abroad"],"AuditChecklist": ["When transferring personal information abroad, has the data subject been fully informed of all notification requirements and obtained separate consent, or complied with certification or recognition, as required by law?","When informing the data subject about the outsourcing or storage of personal information abroad for the purpose of contract execution, are all necessary details included and communicated appropriately?","Has a contract for the transfer of personal information abroad been established, including compliance with personal information protection laws?","Are necessary measures being taken to protect personal information when transferring it abroad?"],"NonComplianceCases": ["Case 1: Personal information was provided to a foreign company during processing, but separate consent for the transfer of personal information abroad was not obtained, even though the conditions for consent exemption (such as certification or recognition by the recipient country) were not met.","Case 2: While using foreign cloud services (foreign regions) for outsourcing and storing personal information, the relevant details, such as the destination country and transfer method, were not disclosed in the privacy policy or communicated to the data subject.","Case 3: While obtaining consent for the transfer of personal information abroad, only the name of the recipient (company name) was disclosed, and the destination country was not properly notified."],"RelatedRegulations": ["Personal Information Protection Act, Articles 28-8 (Transfer of Personal Information Abroad), 28-9 (Order to Suspend Transfer of Personal Information Abroad), 28-10 (Reciprocity), 28-11 (Applicable Provisions)","Regulations on the Operation of Personal Information Transfer Abroad"]}],"description": "When transferring personal information abroad, appropriate protective measures such as obtaining consent and disclosing relevant details about the transfer must be established and implemented.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3.4.1": {"name": "Destruction of Personal Information","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.4.1 Destruction of Personal Information","Subdomain": "3.4. Protection Measures When Destroying Personal Information","AuditEvidence": ["Regulations regarding the retention period and destruction of personal information","Destruction results (e.g., from member databases)","Personal information destruction management records"],"AuditChecklist": ["Has an internal policy been established regarding the retention period and destruction of personal information?","Is personal information being destroyed without delay when the processing purpose is achieved or the retention period has expired?","Is personal information destroyed using safe methods that prevent recovery or reconstruction?","Are records kept of the destruction of personal information and managed properly?"],"NonComplianceCases": ["Case 1: When a member withdraws or the purpose of retention is achieved, personal information was destroyed from the member database, but not from associated systems (CRM, DW) where duplicate personal information was stored.","Case 2: Personal information collected during a specific event was not destroyed or no destruction policy was established, even after the event ended.","Case 3: Personal information collected through a call center (such as call logs, recordings) is retained for three years under the Electronic Commerce Act, but the information was not destroyed even after three years had passed.","Case 4: Due to technical limitations, such as using blockchain, it was not possible to completely destroy personal information, so it was anonymized instead. However, the anonymization process was not done properly, allowing partial re-identification of personal information."],"RelatedRegulations": ["Personal Information Protection Act, Article 21 (Destruction of Personal Information)","Standards for Ensuring the Safety of Personal Information, Article 13 (Destruction of Personal Information)"]}],"description": "The organization must establish an internal policy regarding retention periods and destruction of personal information. When the retention period has expired or the purpose of processing has been achieved, personal information must be destroyed without delay using methods that ensure safety and completeness.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.4.2": {"name": "Measures When Retaining Personal Information After Purpose Is Achieved","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.4.2 Measures When Retaining Personal Information After Purpose Is Achieved","Subdomain": "3.4. Protection Measures When Destroying Personal Information","AuditEvidence": ["Regulations regarding the retention period and destruction of personal information","Current status of separated databases (table structure, etc.)","Access permissions for separated databases"],"AuditChecklist": ["When personal information is retained beyond the retention period or after the processing purpose has been achieved, in accordance with relevant laws, is it limited to the minimum necessary period and only the minimum necessary information?","When personal information is retained beyond the retention period or after the processing purpose has been achieved, is it stored separately from other personal information?","Is personal information that is stored separately processed only within the scope allowed by law?","Is access to separately stored personal information limited to the minimum number of personnel?"],"NonComplianceCases": ["Case 1: Information from withdrawn members was not destroyed but kept for a certain period under the Electronic Commerce Act, with only the flag value changed, and stored in the same table as other member information.","Case 2: Records related to consumer complaints and disputes were kept for five years instead of the required three years, due to misinterpretation of legal requirements.","Case 3: Although a separate database was set up, access permissions were not appropriately configured, allowing personnel who did not require access to view the separated database.","Case 4: Information from withdrawn members was stored separately in accordance with the Electronic Commerce Act, but excessive optional information was also stored, even though there was no legal obligation to do so."],"RelatedRegulations": ["Personal Information Protection Act, Article 21 (Destruction of Personal Information)"]}],"description": "If personal information is retained beyond the retention period or after the purpose of processing has been achieved, as permitted by relevant laws, it must be limited to the minimum necessary items and stored separately from other personal information.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.5.1": {"name": "Disclosure of Privacy Policy","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.5.1 Disclosure of Privacy Policy","Subdomain": "3.5. Protection of Data Subject's Rights","AuditEvidence": ["Privacy policy","Records of privacy policy amendments (e.g., board notices)"],"AuditChecklist": ["Is the privacy policy written in clear and easy-to-understand language, covering all the contents required by law?","Is the privacy policy continuously updated and made easily accessible to data subjects via the internet or other means?","When the privacy policy is updated, are the reasons for the changes and the contents of the changes promptly notified, and can the data subjects easily recognize the changes at any time?"],"NonComplianceCases": ["Case 1: The privacy policy discloses information about the collection and provision of personal information, but the actual details differ from what is being collected and provided.","Case 2: Changes such as the replacement of the privacy officer or changes in subcontractors have occurred, but these changes have not been reflected in the privacy policy.","Case 3: The privacy policy is disclosed, but it is labeled 'Privacy Protection Policy' instead of 'Privacy Policy,' and its visibility is not enhanced with larger font sizes or color to make it easy for data subjects to find.","Case 4: Several amendments have been made to the privacy policy, but older versions of the policy are not made available for review.","Case 5: Although personal information is retained in compliance with laws such as the Electronic Commerce Act and the Commercial Act, the legal grounds for retention and the retained personal information items are not disclosed in the privacy policy."],"RelatedRegulations": ["Personal Information Protection Act, Article 30 (Establishment and Disclosure of Privacy Policy), Article 30-2 (Evaluation and Improvement Recommendations for Privacy Policy)"]}],"description": "A privacy policy must be established to include all necessary information, such as the purpose of personal information processing, in a way that is easy for data subjects to understand. The policy must be disclosed through appropriate methods so that data subjects can easily access it at any time, and it must be continuously updated.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.5.2": {"name": "Guaranteeing Data Subject's Rights","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.5.2 Guaranteeing Data Subject's Rights","Subdomain": "3.5. Protection of Data Subject's Rights","AuditEvidence": ["Privacy policy","Procedures and forms for handling Requests for Access, etc.","Records of actions taken in response to Requests for Access, etc.","Procedures for member withdrawal and consent withdrawal"],"AuditChecklist": ["Are procedures in place to ensure that data subjects or their representatives can exercise their rights (hereinafter referred to as 'Requests for Access, etc.') to access, rectify, delete, or suspend the processing of their personal information in a way that is not more difficult than the process used for collecting it?","When data subjects or their representatives submit Requests for Access, etc., are the necessary measures taken within the required time frame?","When data subjects withdraw their consent to the collection, use, or provision of their personal information, are the collected personal information and associated data promptly deleted or otherwise handled appropriately?","Are appropriate procedures in place to allow data subjects to object to the actions taken regarding their Requests for Access, etc., and are they informed of these procedures?","Are records kept of data subjects' Requests for Access, etc., and the resulting actions?","When the rights of others, such as privacy or honor, are violated on information networks, does the organization have procedures for the affected individuals to request the deletion of the information from service providers, and are these procedures being implemented?"],"NonComplianceCases": ["Case 1: The method for requesting access, rectification, deletion, or suspension of personal information is not disclosed in a way that data subjects can easily find.","Case 2: There has been no response to access requests for personal information within 10 days, without any valid reason.","Case 3: Records of actions taken in response to personal information access requests are not maintained.","Case 4: Access notifications are being sent without verifying whether the requester is the data subject or their legitimate representative.","Case 5: There has been a failure to respond to rectification or deletion requests within 10 days.","Case 6: It was easy to sign up online as a member, but to withdraw membership, additional documents such as ID must be submitted, or in-person visits are required."],"RelatedRegulations": ["Personal Information Protection Act, Article 34-2 (Deletion or Blocking of Exposed Personal Information), Article 35 (Access to Personal Information), Article 35-2 (Right to Data Portability), Article 36 (Rectification or Deletion of Personal Information), Article 37 (Suspension of Processing, etc.), Article 37-2 (Right of Data Subjects to Contest Automated Decisions), Article 38 (Methods and Procedures for Exercising Rights)","Information and Communications Network Act, Article 44 (Protection of Rights in Information Networks), Article 44-2 (Request for Deletion of Information, etc.), Article 44-3 (Temporary Measures)"]}],"description": "Procedures must be established and implemented to ensure that data subjects can easily exercise their rights, such as requesting access, rectification, deletion, suspension of processing, objection, or withdrawal of consent, through simpler processes than those used for collecting their information. When a request is received, it must be processed without delay, and records must be kept. Measures such as deletion requests and temporary actions must be taken to prevent the distribution of information that infringes on the rights of others, such as invasion of privacy or defamation.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"3.5.3": {"name": "Notification to Data Subjects","checks": {},"status": "PASS","attributes": [{"Domain": "3. Requirements for Each Stage of Personal Information Processing","Section": "3.5.3 Notification to Data Subjects","Subdomain": "3.5. Protection of Data Subject's Rights","AuditEvidence": ["Records of notifications regarding the use and provision of personal information","Forms and wording used for notifications regarding the use and provision of personal information"],"AuditChecklist": ["If the organization is legally obligated to do so, does it periodically notify data subjects of the use and provision of their personal information, or provide them with access to an information system where they can review such details?","Do the notification items regarding the use and provision of personal information include all legally required elements?"],"NonComplianceCases": ["Case 1: Although the organization is required to notify data subjects of the use and provision of their personal information, no notifications have been sent during the year despite being obligated due to handling personal information of more than 1 million people on a daily average for the past three months at the end of the previous year.","Case 2: Instead of directly notifying individual data subjects, notifications about the use and provision of personal information were made through simple pop-ups or general announcements on the website."],"RelatedRegulations": ["Personal Information Protection Act, Article 20-2 (Notification of Use and Provision of Personal Information)"]}],"description": "The organization must identify matters that must be notified to data subjects, such as the use and provision of personal information, and periodically inform the data subjects of these matters.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.10.1": {"name": "Security System Operation","checks": {"kms_cmk_are_used": null,"macie_is_enabled": "PASS","securityhub_enabled": "PASS","fms_policy_compliant": null,"guardduty_is_enabled": "PASS","inspector2_is_enabled": "FAIL","elbv2_waf_acl_attached": "FAIL","kms_cmk_rotation_enabled": null,"ec2_securitygroup_not_used": "FAIL","guardduty_centrally_managed": "FAIL","wafv2_webacl_logging_enabled": "FAIL","ssm_managed_compliant_patching": "FAIL","kms_key_not_publicly_accessible": null,"ssmincidents_enabled_with_plans": null,"inspector2_active_findings_exist": "FAIL","cloudfront_distributions_using_waf": null,"cognito_user_pool_waf_acl_attached": null,"trustedadvisor_errors_and_warnings": null,"apigateway_restapi_waf_acl_attached": "FAIL","config_recorder_all_regions_enabled": null,"guardduty_no_high_severity_findings": "FAIL","ec2_securitygroup_from_launch_wizard": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL","organizations_delegated_administrators": null,"ec2_networkacl_allow_ingress_tcp_port_22": "FAIL","ec2_instance_port_ftp_exposed_to_internet": "PASS","ec2_instance_port_rdp_exposed_to_internet": "PASS","ec2_instance_port_ssh_exposed_to_internet": "PASS","secretsmanager_automatic_rotation_enabled": "FAIL","ec2_instance_port_cifs_exposed_to_internet": "PASS","ec2_instance_port_ldap_exposed_to_internet": "PASS","ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_instance_port_kafka_exposed_to_internet": "PASS","ec2_instance_port_mysql_exposed_to_internet": "PASS","ec2_instance_port_redis_exposed_to_internet": "PASS","ec2_instance_port_oracle_exposed_to_internet": "PASS","ec2_instance_port_telnet_exposed_to_internet": "PASS","ec2_instance_port_mongodb_exposed_to_internet": "PASS","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_instance_port_kerberos_exposed_to_internet": "PASS","ec2_instance_port_cassandra_exposed_to_internet": "PASS","ec2_instance_port_memcached_exposed_to_internet": "PASS","ec2_instance_port_sqlserver_exposed_to_internet": "PASS","cloudwatch_log_metric_filter_sign_in_without_mfa": null,"ec2_instance_port_postgresql_exposed_to_internet": "PASS","ec2_securitygroup_with_many_ingress_egress_rules": "PASS","shield_advanced_protection_in_global_accelerators": null,"ec2_instance_internet_facing_with_instance_profile": "FAIL","shield_advanced_protection_in_route53_hosted_zones": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_authentication_failures": null,"shield_advanced_protection_in_associated_elastic_ips": null,"shield_advanced_protection_in_classic_load_balancers": null,"shield_advanced_protection_in_cloudfront_distributions": null,"ec2_securitygroup_allow_ingress_from_internet_to_any_port": "PASS","ec2_instance_port_elasticsearch_kibana_exposed_to_internet": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","shield_advanced_protection_in_internet_facing_load_balancers": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.10.1 Security System Operation","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Security system configuration","Network configuration","Security system operational procedures","Firewall policies","Firewall policy setup/modification request forms","Exception list for the security system","Management screens for each security system (firewall, IPS, server access control, DLP, DRM, etc.)","Security system policy review history"],"AuditChecklist": ["Has the organization established and implemented operational procedures for the security systems in use?","Is access to the security system administrators limited to a minimum, and is unauthorized access strictly controlled?","Has the organization established and implemented formal procedures for registering, modifying, and deleting policies for each security system?","Are exception policies for the security system managed according to procedures, and are users of exception policies managed with the minimum privileges?","Is the validity of the policies set on the security system periodically reviewed?","Has the organization installed and operated security systems that perform functions specified by law to prevent illegal access and data leakage in personal information processing systems?"],"NonComplianceCases": ["Case 1: Regular reviews of the security policies for the intrusion prevention system were not conducted, resulting in unnecessary or excessively permissive policies.","Case 2: There are no procedures or criteria for applying, modifying, or deleting security policies, or such procedures exist but are not followed.","Case 3: The assignment and supervision of administrators for the security system were not properly implemented.","Case 4: Although internal guidelines stipulate that the information security officer must record and maintain the history of security policy changes for the security system, the policy management ledger was not periodically maintained, or the policies recorded in the ledger did not match those actually applied in the operating system."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "For each type of security system, an administrator must be designated, and operational procedures such as updating to the latest policies, modifying rule sets, and monitoring events must be established and implemented. The status of policy application for each security system must be managed.","checks_status": {"fail": 16,"pass": 39,"total": 75,"manual": 0}},"2.10.2": {"name": "Cloud Security","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protective Measure Requirements","Section": "2.10.2 Cloud Security","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Cloud service-related contracts and SLA","Cloud service risk analysis results","Cloud service security control policies","Cloud service administrator privilege assignment status","Cloud service architecture diagram","Cloud service security setting status","Cloud service security setting appropriateness review history"],"AuditChecklist": ["Is the responsibility and role for information protection and personal information protection clearly defined with the cloud service provider, and is it reflected in contracts (such as SLA)?","Are security risks based on the service type evaluated when using cloud services, and are security control policies established and implemented, including security configurations and setting standards, security setting changes and approval procedures, secure connection methods, and authority systems to prevent unauthorized access and configuration errors?","Are administrator privileges for cloud services granted minimally according to roles, and are enhanced protection measures such as strengthened authentication, encryption, access control, and audit logs applied to prevent unauthorized access and abuse of privileges?","Is the monitoring of cloud service security setting changes and operation status conducted, and is the appropriateness of these settings reviewed regularly?"],"NonComplianceCases": ["Case 1: The cloud service contract does not include responsibilities and roles related to security.","Case 2: Employees without a business need have been excessively granted permissions to change the security settings of the cloud service.","Case 3: Internal guidelines require security officer approval when changing access control rules in the private network of the cloud, but many access control rules were registered or changed without following the approval procedure.","Case 4: Due to security setting errors in the cloud service, internal log files were exposed to the internet."],"RelatedRegulations": []}],"description": "When using cloud services, protection measures must be established and implemented for administrator access and security settings to prevent unauthorized access and configuration errors that could lead to the leakage or exposure of critical information and personal data, depending on the service type (SaaS, PaaS, IaaS, etc.).","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.10.3": {"name": "Public Server Security","checks": {"elb_ssl_listeners": "FAIL","elbv2_ssl_listeners": "FAIL","ssm_document_secrets": "PASS","elbv2_waf_acl_attached": "FAIL","elb_insecure_ssl_ciphers": "PASS","apigateway_restapi_public": "FAIL","lightsail_database_public": null,"lightsail_instance_public": null,"elbv2_insecure_ssl_ciphers": "PASS","lightsail_static_ip_unused": null,"networkfirewall_in_all_vpc": "FAIL","ec2_instance_imdsv2_enabled": "PASS","elbv2_desync_mitigation_mode": "FAIL","awslambda_function_inside_vpc": "FAIL","awslambda_function_url_public": null,"ec2_instance_secrets_user_data": "PASS","ec2_launch_template_no_secrets": "PASS","ssm_managed_compliant_patching": "FAIL","inspector2_active_findings_exist": "FAIL","acm_certificates_expiration_check": "PASS","awslambda_function_url_cors_policy": null,"cloudfront_distributions_using_waf": null,"vpc_subnet_separate_private_public": "FAIL","apigateway_restapi_waf_acl_attached": "FAIL","apigatewayv2_api_authorizers_enabled": "FAIL","awslambda_function_no_secrets_in_code": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","apigateway_restapi_authorizers_enabled": "PASS","cloudfront_distributions_https_enabled": null,"ec2_networkacl_allow_ingress_tcp_port_22": "FAIL","apigateway_restapi_public_with_authorizer": "FAIL","ec2_instance_port_ftp_exposed_to_internet": "PASS","ec2_instance_port_rdp_exposed_to_internet": "PASS","ec2_instance_port_ssh_exposed_to_internet": "PASS","awslambda_function_no_secrets_in_variables": "PASS","awslambda_function_not_publicly_accessible": "PASS","ec2_instance_port_cifs_exposed_to_internet": "PASS","ec2_networkacl_allow_ingress_tcp_port_3389": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","route53_domains_privacy_protection_enabled": null,"ec2_instance_port_kafka_exposed_to_internet": "PASS","ec2_instance_port_mysql_exposed_to_internet": "PASS","ec2_instance_port_redis_exposed_to_internet": "PASS","ec2_instance_port_oracle_exposed_to_internet": "PASS","ec2_instance_port_telnet_exposed_to_internet": "PASS","apigateway_restapi_client_certificate_enabled": "FAIL","ec2_instance_port_mongodb_exposed_to_internet": "PASS","ec2_securitygroup_allow_wide_open_public_ipv4": "PASS","ec2_instance_port_kerberos_exposed_to_internet": "PASS","ec2_instance_port_cassandra_exposed_to_internet": "PASS","ec2_instance_port_memcached_exposed_to_internet": "PASS","ec2_instance_port_sqlserver_exposed_to_internet": "PASS","kafka_cluster_mutual_tls_authentication_enabled": null,"ec2_instance_port_postgresql_exposed_to_internet": "PASS","ec2_securitygroup_with_many_ingress_egress_rules": "PASS","autoscaling_find_secrets_ec2_launch_configuration": "PASS","ec2_instance_internet_facing_with_instance_profile": "FAIL","cloudfront_distributions_using_deprecated_ssl_protocols": null,"ec2_securitygroup_allow_ingress_from_internet_to_any_port": "PASS","ec2_instance_port_elasticsearch_kibana_exposed_to_internet": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_all_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_high_risk_tcp_ports": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_redis_6379": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Protective Measure Requirements","Section": "2.10.3 Public Server Security","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Network diagram","Website information disclosure procedures and history (e.g., requests, approvals, posting history)","Inspection history of personal and sensitive information exposure"],"AuditChecklist": ["Are protective measures established and implemented for the operation of public servers?","Are public servers installed in a DMZ separated from internal networks and protected by security systems such as firewalls?","When posting or storing personal or sensitive information on public servers, are approval and posting procedures, including obtaining approval from the responsible person, established and followed?","Does the organization regularly check whether sensitive information is being exposed through websites and web servers, and if exposure is detected, are measures taken immediately to block it?"],"NonComplianceCases": ["Case 1: Due to vulnerabilities in publicly exposed websites, unauthorized individuals were able to access others' personal information through Google search.","Case 2: Although internal regulations require approval procedures before posting personal information on websites, there were multiple cases where personal information was posted without following these procedures.","Case 3: In web applications such as bulletin boards, it was possible to arbitrarily modify or delete posts made by others, or view password-protected posts."],"RelatedRegulations": []}],"description": "For servers exposed to external networks, protective measures must be established and implemented, including separating them from internal networks, conducting vulnerability assessments, access control, authentication, and establishing procedures for information collection, storage, and disclosure.","checks_status": {"fail": 19,"pass": 47,"total": 76,"manual": 0}},"2.10.4": {"name": "Security for Electronic Transactions and FinTech","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.10.4 Security for Electronic Transactions and FinTech","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Protection measures for electronic transaction and FinTech services","Security review results for payment system integration"],"AuditChecklist": ["Are protection measures established and implemented to ensure the safety and reliability of transactions when providing electronic transaction and FinTech services?","Are protection measures established and implemented to protect transmitted information when integrating with external systems, such as payment systems, and is the security of the integration checked?"],"NonComplianceCases": ["Case 1: While a contract was made with a payment service provider and integration was established, all payment-related information was transmitted in plain text through a specific URL without appropriate authentication or access restrictions.","Case 2: Although the external payment system was connected via a dedicated network, internal business systems were not properly controlled by firewalls or other security measures.","Case 3: Although internal guidelines required a security review by the information protection team before integrating external FinTech services, the review was skipped due to scheduling reasons when integrating a new FinTech service."],"RelatedRegulations": []}],"description": "When providing electronic transaction and FinTech services, protection measures such as authentication and encryption must be established to prevent data leakage, data tampering, or fraud. The security of external systems, such as payment systems, must be checked when integrated.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.10.5": {"name": "Secure Information Transmission","checks": {"elb_ssl_listeners": "FAIL","elbv2_ssl_listeners": "FAIL","elb_insecure_ssl_ciphers": "PASS","elbv2_insecure_ssl_ciphers": "PASS","rds_instance_transport_encrypted": "FAIL","s3_bucket_secure_transport_policy": "FAIL","glue_database_connections_ssl_enabled": null,"cloudfront_distributions_https_enabled": null,"sns_subscription_not_using_http_endpoints": "PASS","kafka_cluster_in_transit_encryption_enabled": null,"apigateway_restapi_client_certificate_enabled": "FAIL","kafka_cluster_mutual_tls_authentication_enabled": null,"directoryservice_radius_server_security_protocol": null,"cloudfront_distributions_using_deprecated_ssl_protocols": null,"elasticache_redis_cluster_in_transit_encryption_enabled": null,"opensearch_service_domains_https_communications_enforced": null,"opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.10.5 Secure Information Transmission","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Information transmission agreement or contract","Technical standards for information transmission","System diagrams and interface definitions related to information transmission"],"AuditChecklist": ["Has a secure transmission policy been established when transmitting personal and critical information to external organizations?","When exchanging personal and critical information between organizations for business purposes, are agreements and protection measures for secure transmission established and implemented?"],"NonComplianceCases": ["Case 1: Although a dedicated network or VPN is applied when integrating with external organizations, there is inadequate management of the timing, method, responsible person, transmitted information, and legal basis for each integration.","Case 2: There is a lack of implementation of security reviews, security standards, and action plans for using weak encryption algorithms (e.g., DES, 3DES) or decrypting during intermediate transmission stages."],"RelatedRegulations": []}],"description": "When transmitting personal or critical information to other organizations, a secure transmission policy must be established, and agreements must be made between organizations regarding management responsibilities, transmission methods, and technical protection measures for personal and critical information.","checks_status": {"fail": 5,"pass": 3,"total": 17,"manual": 0}},"2.10.6": {"name": "Security for Business Devices","checks": {"workspaces_volume_encryption_enabled": null,"appstream_fleet_maximum_session_duration": null,"appstream_fleet_session_disconnect_timeout": null,"workspaces_vpc_2private_1public_subnets_nat": null,"appstream_fleet_session_idle_disconnect_timeout": null,"appstream_fleet_default_internet_access_disabled": null},"status": "PASS","attributes": [{"Domain": "2. Protection Measure Requirements","Section": "2.10.6 Security for Business Devices","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Security control guidelines and procedures for business devices","Registration status of business devices","Security settings for business devices","Authentication and approval history for business devices","Security check status for business devices"],"AuditChecklist": ["Are security control policies, such as device authentication, approval, access scope, and security settings, established and implemented for devices used for business purposes, such as PCs, laptops, virtual PCs, and tablets?","Are policies established and implemented to prevent the leakage of personal and critical information through business devices by prohibiting the use of file-sharing programs, limiting shared settings, and controlling wireless network usage?","Are security measures applied to prevent the leakage of personal and critical information in case of loss or theft of business mobile devices?","Is the appropriateness of access control measures for business devices periodically reviewed?"],"NonComplianceCases": ["Case 1: Although laptops and tablet PCs are used for business purposes, there are no policies established for device approval, usage scope, approval procedures, or authentication methods.","Case 2: The security management guidelines for mobile devices prohibit the use of mobile devices for business purposes unless specifically approved, but unapproved mobile devices are still being used to access internal information systems.","Case 3: Personal and critical information is handled on mobile devices, but security measures such as password protection are not applied to prevent leaks due to loss or theft.","Case 4: Although internal regulations prohibit the use of shared folders on business devices, periodic checks are not conducted, resulting in excessive use of shared folders on many business devices."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "When connecting devices such as PCs and mobile devices to the network for business purposes, access control measures such as device authentication, approval, access scope, and security settings must be established and periodically checked.","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"2.10.7": {"name": "Management of Removable Media","checks": {},"status": "PASS","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.10.7 Management of Removable Media","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Policy on blocking removable media (USB, CD, etc.)","Removable media management log","Inspection records of removable media status"],"AuditChecklist": ["Are policies and procedures established and implemented for handling (use), storage, disposal, and reuse of removable media such as external hard drives, USB memory, and CDs?","Is the status of ownership, use, and management of removable media periodically checked?","Is the use of removable media restricted in controlled areas, such as key information systems or important restricted areas?","Are measures in place to prevent the infection of malware and the leakage of important information through removable media?","Are removable media containing personal or important information stored in a secure location with locking mechanisms?"],"NonComplianceCases": ["Case 1: Although there is a policy restricting the use of removable media in controlled areas like server rooms, several cases were found where removable media was used without following the exception approval process, and periodic inspections of the removable media management status were not conducted, resulting in inadequate updates to the management log.","Case 2: Removable media containing personal information was not stored in a secure location with locking mechanisms and was left unattended in office drawers.","Case 3: Although a solution to control removable media was implemented, some users were granted write access without appropriate approval procedures.","Case 4: Some common PCs and IT equipment in the server room allowed writing to standard USB memory devices, but controls such as media import and usage restrictions, usage history records, and reviews were not applied."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 10 (Physical Safety Measures)"]}],"description": "Procedures must be established and implemented to prevent the leakage of personal or important information or infection by malware through removable media. Removable media containing personal or important information must be stored in a secure location.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.10.8": {"name": "Patch Management","checks": {"ssm_managed_compliant_patching": "FAIL","kafka_cluster_uses_latest_version": null,"ec2_instance_account_imdsv2_enabled": null,"redshift_cluster_automatic_upgrades": null,"eks_cluster_uses_a_supported_version": null,"ec2_instance_older_than_specific_days": "FAIL","rds_instance_deprecated_engine_version": "PASS","rds_cluster_minor_version_upgrade_enabled": "PASS","dms_instance_minor_version_upgrade_enabled": null,"rds_instance_minor_version_upgrade_enabled": "PASS","awslambda_function_using_supported_runtimes": "FAIL","elasticache_redis_cluster_auto_minor_version_upgrades": null,"cloudfront_distributions_using_deprecated_ssl_protocols": null,"opensearch_service_domains_updated_to_the_latest_service_software_version": null},"status": "FAIL","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.10.8 Patch Management","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Patch management policies and procedures","Patch status of each system","Impact analysis results related to patch application"],"AuditChecklist": ["Are patch management policies and procedures for operating systems (OS) and software established and implemented according to the characteristics and importance of each asset, such as servers, network systems, security systems, and PCs?","Are the patch status of installed OS and software on key servers, network systems, and security systems periodically managed?","If applying the latest patches to address vulnerabilities is difficult due to service impact, are alternative measures implemented?","Is the application of patches via public internet access restricted for key servers, network systems, and security systems?","When using a patch management system, are sufficient protection measures, such as access control, established?"],"NonComplianceCases": ["Case 1: In some systems, OS patches were not applied for a long period without valid reasons or approval from the responsible personnel.","Case 2: Some systems were using OS versions that were no longer supported (EOS), but no response plans or alternative measures were in place.","Case 3: Although the latest patches were applied to commercial software and OS, there were no procedures or personnel assigned to confirm and apply the latest patches for open-source programs (e.g., OpenSSL, OpenSSH, Apache), resulting in the lack of application of the latest security patches."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 9 (Prevention of Malware, etc.)"]}],"description": "To prevent security incidents due to vulnerabilities in software, operating systems, or security systems, the latest patches must be applied. However, if the application of the latest patches is difficult due to service impact considerations, alternative measures must be implemented.","checks_status": {"fail": 3,"pass": 3,"total": 14,"manual": 0}},"2.10.9": {"name": "Malware Control","checks": {},"status": "PASS","attributes": [{"Domain": "2. Security Control Requirements","Section": "2.10.9 Malware Control","Subdomain": "2.10. System and Service Security Management","AuditEvidence": ["Guidelines, procedures, and manuals for malware response","Antivirus program installation status","Antivirus program configuration screens","Malware response history (e.g., response reports)"],"AuditChecklist": ["Are protection measures established and implemented to protect information systems and business terminals from malware such as viruses, worms, Trojans, and ransomware?","Are prevention and detection activities for the latest malware continuously performed using security programs such as antivirus software?","Are security programs such as antivirus software kept up to date, and are emergency security updates performed when necessary?","Are procedures for response, such as minimizing the spread of malware and mitigating damage, established and implemented when malware infections are discovered?"],"NonComplianceCases": ["Case 1: Some PCs and servers do not have antivirus software installed, or the antivirus engine has not been updated to the latest version for a long time.","Case 2: Although users can change the antivirus program settings (e.g., real-time scanning, scheduled scanning, update settings) at their discretion, no additional protection measures were established to address this.","Case 3: Insufficient protection measures, such as access control, were in place for the central antivirus management system, leading to the possibility of security incidents through the central management system, or no integrity verification of the antivirus pattern was performed, making it possible for malware to spread through malicious users.","Case 4: Although multiple malware infections were confirmed on some internal network PCs and servers, there was no confirmation of the infection status, infection routes, cause analysis, or resulting actions."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 9 (Prevention of Malware, etc.)"]}],"description": "To protect personal and important information, information systems, and business terminals from malware such as viruses, worms, Trojans, and ransomware, prevention, detection, and response measures must be established and implemented.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.11.1": {"name": "Establishment of Incident Prevention and Response System","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.11.1 Establishment of Incident Prevention and Response System","Subdomain": "2.11. Incident Prevention and Response","AuditEvidence": ["Incident response guidelines/procedures/manual","Incident response organization chart and emergency contact list","Security monitoring service contract (SLA, etc.)"],"AuditChecklist": ["Has the organization established procedures and systems to prevent security breaches and personal information leaks and to respond quickly and effectively when incidents occur?","If the organization is operating an incident response system through an external institution, such as a security monitoring service, are the details of the incident response procedures reflected in the contract?","Has the organization established a cooperative system with external experts, specialized companies, or institutions for monitoring, responding to, and handling security incidents?"],"NonComplianceCases": ["Case 1: Failure to clearly define the incident response organization and procedures for responding to security breaches.","Case 2: Although internal guidelines and procedures specify incident response steps for different phases (before, during, after detection, recovery, reporting, etc.), some or all of the response and recovery procedures for specific incident types and severity levels are not established.","Case 3: Failure to keep the incident response organization chart and emergency contact list up to date, or the roles and responsibilities of each team member are not clearly defined.","Case 4: Errors or outdated information in the contact details for external agencies responsible for incident reporting, notification, and cooperation, or failure to keep some agency details current.","Case 5: When outsourcing incident detection and response to an external security monitoring company or related institution, failure to clearly define the roles and responsibilities for both parties in the contract or SLA.","Case 6: Although incident response procedures are in place, they do not meet the legal requirements for reporting and notifying personal data breaches, such as criteria and timing."],"RelatedRegulations": ["Personal Information Protection Act, Article 34 (Notification and Reporting of Personal Information Leaks, etc.)","Information and Communications Network Act, Article 48-3 (Reporting of Security Incidents), Article 48-4 (Analysis of Causes of Security Incidents, etc.)"]}],"description": "To prevent incidents such as security breaches and personal information leaks, and to respond quickly and effectively in the event of an incident, the organization must establish procedures for detecting, responding to, analyzing, and sharing internal and external intrusion attempts. In addition, the organization must establish a cooperative system with relevant external institutions and experts.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.11.2": {"name": "Vulnerability Inspection and Remediation","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ssm_document_secrets": "PASS","inspector2_is_enabled": "FAIL","ec2_instance_imdsv2_enabled": "PASS","guardduty_centrally_managed": "FAIL","ec2_instance_secrets_user_data": "PASS","ec2_launch_template_no_secrets": "PASS","inspector2_active_findings_exist": "FAIL","trustedadvisor_errors_and_warnings": null,"guardduty_no_high_severity_findings": "FAIL","awslambda_function_no_secrets_in_code": "PASS","cloudwatch_log_group_no_secrets_in_logs": "FAIL","ecr_registry_scan_images_on_push_enabled": "PASS","cloudformation_stack_outputs_find_secrets": "PASS","codebuild_project_no_secrets_in_variables": "PASS","awslambda_function_no_secrets_in_variables": "PASS","ecs_task_definitions_no_environment_secrets": "PASS","ecr_repositories_scan_images_on_push_enabled": "FAIL","trustedadvisor_premium_support_plan_subscribed": null,"autoscaling_find_secrets_ec2_launch_configuration": "PASS","ecr_repositories_scan_vulnerabilities_in_latest_image": null,"codebuild_project_source_repo_url_no_sensitive_credentials": "PASS"},"status": "FAIL","attributes": [{"Domain": "2. Protective Measures Requirements","Section": "2.11.2 Vulnerability Inspection and Remediation","Subdomain": "2.11. Incident Prevention and Response","AuditEvidence": ["Vulnerability inspection plan","Vulnerability inspection report (for web, mobile apps, servers, network systems, security systems, DBMS, etc.)","Vulnerability inspection records","Vulnerability remediation plan","Vulnerability remediation completion report","Penetration testing plan/results report"],"AuditChecklist": ["Has the organization established and implemented procedures for conducting regular vulnerability inspections of information systems?","Are actions taken to address identified vulnerabilities, and are the results reported to the responsible authorities?","Does the organization continuously monitor for new security vulnerabilities and assess their impact on the information systems, taking appropriate actions?","Is a record of vulnerability inspections maintained, and are protective measures implemented to address recurring vulnerabilities identified in previous years?"],"NonComplianceCases": ["Case 1: Although internal regulations require annual technical vulnerability inspections for major systems, some major systems were excluded from the inspection.","Case 2: Failure to implement corrective actions for identified vulnerabilities, or failure to provide justification and approval records for vulnerabilities that cannot be addressed promptly."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 4 (Establishment, Implementation, and Inspection of Internal Management Plans), Article 6 (Access Control)"]}],"description": "Regular vulnerability inspections must be conducted to verify whether information systems have exposed vulnerabilities, and any identified vulnerabilities must be promptly addressed. In addition, the organization must continuously monitor for new security vulnerabilities, assess their impact on the information systems, and take necessary actions.","checks_status": {"fail": 6,"pass": 14,"total": 23,"manual": 0}},"2.11.3": {"name": "Abnormal Behavior Analysis and Monitoring","checks": {"securityhub_enabled": "PASS","fms_policy_compliant": null,"vpc_flow_logs_enabled": "FAIL","cloudtrail_insights_exist": null,"networkfirewall_in_all_vpc": "FAIL","trustedadvisor_errors_and_warnings": null,"guardduty_no_high_severity_findings": "FAIL","cloudtrail_threat_detection_enumeration": null,"cloudwatch_log_group_no_secrets_in_logs": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"cloudwatch_cross_account_sharing_disabled": null,"cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_log_metric_filter_aws_organizations_changes": null,"cognito_user_pool_client_prevent_user_existence_errors": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL","cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.11.3 Abnormal Behavior Analysis and Monitoring","Subdomain": "2.11. Incident Prevention and Response","AuditEvidence": ["Status of abnormal behavior analysis and monitoring","Evidence of responses taken when abnormal behaviors were detected"],"AuditChecklist": ["Is the organization collecting, analyzing, and monitoring network traffic, data flows, and event logs from major information systems, applications, networks, and security systems to detect abnormal behaviors such as intrusion attempts, personal information leakage attempts, or fraudulent activities?","Has the organization defined criteria and thresholds to determine abnormal behaviors, and is follow-up action, such as the determination and investigation of abnormal activities, taken in a timely manner?"],"NonComplianceCases": ["Case 1: Failure to establish a real-time or regular monitoring system and procedures to detect intrusion attempts on servers, networks, databases, and security systems from external sources.","Case 2: Although the organization has outsourced monitoring tasks to an external security monitoring agency, there is no record of reviewing the reports provided by the agency, and the organization does not have its own monitoring system for systems excluded from the outsourced service.","Case 3: Although abnormal traffic exceeding internally defined thresholds has been continuously detected, no response measures have been taken."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 6 (Access Control)"]}],"description": "To quickly detect and respond to intrusion attempts, personal information leakage attempts, and fraudulent activities from internal or external sources, the organization must collect and analyze network and data flows. Post-monitoring and inspection actions must be timely.","checks_status": {"fail": 6,"pass": 1,"total": 28,"manual": 0}},"2.11.4": {"name": "Incident Response Training and Improvement","checks": {"ssmincidents_enabled_with_plans": null},"status": "PASS","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.11.4 Incident Response Training and Improvement","Subdomain": "2.11. Incident Prevention and Response","AuditEvidence": ["Simulation training plan for responding to security and personal information leakage incidents","Simulation training result reports for responding to security and personal information leakage incidents","Incident response procedures"],"AuditChecklist": ["Has the organization established a simulation training plan for responding to security incidents and personal information leakage incidents, and are such training exercises conducted at least once a year?","Is the organization reflecting the results of security incident and personal information leakage incident training to improve its response system?"],"NonComplianceCases": ["Case 1: Failure to conduct simulation training or provide related training plans and result reports.","Case 2: Although an annual simulation training plan for security incidents was established, it was not conducted within the planned period without valid reason or approval.","Case 3: Simulation training was conducted, but it was not performed according to the procedures and forms defined in the internal guidelines."],"RelatedRegulations": []}],"description": "The organization must conduct at least one simulation training per year based on scenarios to ensure that employees and stakeholders are familiar with the procedures for responding to security incidents and personal information leakage incidents. The response system must be improved based on the training results.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"2.11.5": {"name": "Incident Response and Recovery","checks": {},"status": "PASS","attributes": [{"Domain": "2. Protection Measures Requirements","Section": "2.11.5 Incident Response and Recovery","Subdomain": "2.11. Incident Prevention and Response","AuditEvidence": ["Incident response procedures","Incident response reports","Incident management logs","Personal information leakage reports","Emergency contact list"],"AuditChecklist": ["When signs of or actual incidents of security breaches or personal information leakage are detected, is the organization responding and reporting promptly according to the defined incident response procedures?","Is the organization notifying data subjects and reporting to relevant authorities as required by law in case of a personal information breach?","After the incident is resolved, is the organization analyzing the cause, reporting the results, and sharing them with relevant departments and personnel?","Is the organization utilizing the information obtained from incident analysis to establish preventive measures to prevent similar incidents from recurring, and if necessary, modifying its incident response procedures?"],"NonComplianceCases": ["Case 1: Although internal incident response guidelines require that security incidents be reported to the internal information protection committee and relevant departments, the department in charge responded to the incident independently without reporting to the information protection committee or relevant departments.","Case 2: Although a service outage suspected to be caused by a DDoS attack occurred recently, the organization did not analyze the cause or establish preventive measures.","Case 3: Although a personal information leakage incident occurred due to external hacking, notification and reporting were not made within 72 hours, citing the small number of affected personal information records as the reason.","Case 4: Although personal information of more than 1,000 individuals was leaked due to an employee's mistake on the company website, the affected data subjects were not notified."],"RelatedRegulations": ["Personal Information Protection Act, Article 34 (Notification and Reporting of Personal Information Leakage)","Information and Communications Network Act, Article 48-3 (Reporting of Security Incidents), Article 48-4 (Analysis of Causes of Security Incidents)"]}],"description": "When signs of or actual incidents of security breaches or personal information leakage are detected, the organization must comply with legal notification and reporting obligations, respond and recover promptly according to established procedures, and analyze the incident to establish preventive measures to reflect in the response system.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"2.12.1": {"name": "Safety Measures for Disaster Preparedness","checks": {"drs_job_exist": "FAIL","backup_plans_exist": "PASS","rds_cluster_multi_az": "FAIL","elb_is_in_multiple_az": "FAIL","rds_instance_multi_az": "FAIL","s3_bucket_object_lock": "FAIL","vpc_different_regions": null,"efs_have_backup_enabled": "FAIL","elbv2_is_in_multiple_az": "PASS","vpc_subnet_different_az": "PASS","backup_reportplans_exist": null,"neptune_cluster_multi_az": null,"elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_lifecycle_enabled": "FAIL","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"autoscaling_group_multiple_az": null,"dms_instance_multi_az_enabled": null,"ec2_ebs_volume_snapshots_exists": "FAIL","rds_cluster_deletion_protection": "FAIL","rds_instance_deletion_protection": "FAIL","documentdb_cluster_backup_enabled": null,"s3_bucket_cross_region_replication": "FAIL","kms_cmk_not_deleted_unintentionally": null,"neptune_cluster_deletion_protection": null,"redshift_cluster_automated_snapshot": null,"elb_cross_zone_load_balancing_enabled": "PASS","lightsail_instance_automated_snapshots": null,"dlm_ebs_snapshot_lifecycle_policy_exists": "FAIL","documentdb_cluster_cloudwatch_log_export": null,"elasticache_redis_cluster_backup_enabled": null,"elasticache_redis_cluster_multi_az_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protective Measure Requirements","Section": "2.12.1 Safety Measures for Disaster Preparedness","Subdomain": "2.12. Disaster Recovery","AuditEvidence": ["IT disaster recovery guidelines/procedures","IT disaster recovery plans (including RTO and RPO definitions)","Emergency contact list","Crisis response manual for personal information processing systems"],"AuditChecklist": ["Has the organization identified IT disaster types that could threaten the continuity of core services (businesses) and analyzed the expected scale of damage and impact on operations to identify core IT services (businesses) and systems?","Has the organization defined recovery time objectives (RTO) and recovery point objectives (RPO) based on the importance and characteristics of core IT services and systems?","Has the organization established and implemented disaster recovery plans, including recovery strategies, emergency recovery teams, emergency contact networks, and recovery procedures, to ensure the continuity of core services and systems during disasters?"],"NonComplianceCases": ["Case 1: The IT disaster recovery procedures lack critical details such as the definition of IT disaster recovery teams and roles, emergency contact systems, and recovery procedures and methods.","Case 2: Although a backup center has been established to ensure the continuity of information systems and minimize damage during emergencies, the relevant policies do not include disaster recovery procedures using the backup center, making disaster recovery tests and actual recovery efforts ineffective.","Case 3: Recovery time objectives for some critical systems related to service operations have not been defined, and appropriate recovery strategies are not in place.","Case 4: The disaster recovery guidelines do not define the recovery priorities, RTO, or RPO for IT services or systems.","Case 5: Unrealistic recovery objectives have been set, either too high or too low, and the RPO and backup policies (e.g., targets, frequency) are not appropriately linked, making it difficult to ensure the effectiveness of recovery."],"RelatedRegulations": ["Personal Information Protection Act, Article 29 (Obligation to Take Safety Measures)","Standards for Ensuring the Safety of Personal Information, Article 11 (Safety Measures for Disaster Preparedness)"]}],"description": "Identify types of disasters that could threaten the operational continuity of the organization's core services and systems, such as natural disasters, communication or power failures, and hacking. Analyze the expected scale of damage and impact for each type, define the recovery time objective (RTO) and recovery point objective (RPO), and establish a disaster recovery system including recovery strategies, emergency recovery teams, emergency contact networks, and recovery procedures.","checks_status": {"fail": 14,"pass": 5,"total": 33,"manual": 0}},"2.12.2": {"name": "Disaster Recovery Testing and Improvement","checks": {"drs_job_exist": "FAIL","backup_plans_exist": "PASS","rds_cluster_multi_az": "FAIL","elb_is_in_multiple_az": "FAIL","rds_instance_multi_az": "FAIL","s3_bucket_object_lock": "FAIL","vpc_different_regions": null,"efs_have_backup_enabled": "FAIL","elbv2_is_in_multiple_az": "PASS","vpc_subnet_different_az": "PASS","backup_reportplans_exist": null,"neptune_cluster_multi_az": null,"elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_lifecycle_enabled": "FAIL","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"autoscaling_group_multiple_az": null,"dms_instance_multi_az_enabled": null,"ec2_ebs_volume_snapshots_exists": "FAIL","rds_cluster_deletion_protection": "FAIL","rds_instance_deletion_protection": "FAIL","documentdb_cluster_backup_enabled": null,"s3_bucket_cross_region_replication": "FAIL","kms_cmk_not_deleted_unintentionally": null,"neptune_cluster_deletion_protection": null,"redshift_cluster_automated_snapshot": null,"elb_cross_zone_load_balancing_enabled": "PASS","lightsail_instance_automated_snapshots": null,"dlm_ebs_snapshot_lifecycle_policy_exists": "FAIL","documentdb_cluster_cloudwatch_log_export": null,"elasticache_redis_cluster_backup_enabled": null,"elasticache_redis_cluster_multi_az_enabled": null},"status": "FAIL","attributes": [{"Domain": "2. Protective Measure Requirements","Section": "2.12.2 Disaster Recovery Testing and Improvement","Subdomain": "2.12. Disaster Recovery","AuditEvidence": ["IT disaster recovery procedures","IT disaster recovery test plans","IT disaster recovery test results"],"AuditChecklist": ["Has the organization established and implemented disaster recovery test plans to evaluate the effectiveness of the established IT disaster recovery system?","Are the disaster recovery strategies and plans regularly reviewed and supplemented to reflect test results, changes in the information system environment, and legal requirements?"],"NonComplianceCases": ["Case 1: Disaster recovery drills were not planned or conducted, and the related plans and result reports are not available.","Case 2: Although a disaster recovery drill plan was established, it was not conducted as planned or approved, and the related result reports are missing.","Case 3: Disaster recovery drills were conducted, but they did not follow the procedures and forms outlined in the internal guidelines, making it difficult to evaluate the adequacy and effectiveness of the disaster recovery procedures."],"RelatedRegulations": []}],"description": "Regularly test the adequacy of the disaster recovery strategies and plans, and supplement the recovery strategies and plans based on test results, changes in the information system environment, and legal requirements.","checks_status": {"fail": 14,"pass": 5,"total": 33,"manual": 0}}},"requirements_passed": 10,"requirements_failed": 27,"requirements_manual": 64,"total_requirements": 101,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "23a633ec-caa6-4021-809a-a247c6f177e6","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "nist_csf_1.1_aws","framework": "NIST-CSF","version": "1.1","description": "The NIST Cybersecurity Framework (CSF) is supported by governments and industries worldwide as a recommended baseline for use by any organization, regardless of sector or size. The NIST Cybersecurity Framework consists of three primary components: the framework core, the profiles, and the implementation tiers. The framework core contains desired cybersecurity activities and outcomes organized into 23 categories that cover the breadth of cybersecurity objectives for an organization. The profiles contain an organization's unique alignment of their organizational requirements and objectives, risk appetite, and resources using the desired outcomes of the framework core. The implementation tiers describe the degree to which an organizationās cybersecurity risk management practices exhibit the characteristics defined in the framework core.","region": "eu-west-1","requirements": {"ac_1": {"name": "PR.AC-1","checks": {"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_password_policy_reuse_24": null,"iam_rotate_access_key_90_days": null,"iam_user_console_access_unused": null,"secretsmanager_automatic_rotation_enabled": "FAIL","iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_1","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes.","checks_status": {"fail": 1,"pass": 0,"total": 9,"manual": 0}},"ac_3": {"name": "PR.AC-3","checks": {"iam_root_mfa_enabled": null,"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"iam_root_hardware_mfa_enabled": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"iam_user_mfa_enabled_console_access": null,"s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_3","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Remote access is managed.","checks_status": {"fail": 3,"pass": 6,"total": 20,"manual": 0}},"ac_4": {"name": "PR.AC-4","checks": {"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_user_console_access_unused": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_4","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Access permissions and authorizations are managed, incorporating the principles of least privilege and separation of duties.","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"ac_5": {"name": "PR.AC-5","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"acm_certificates_expiration_check": "PASS","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_5","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Network integrity is protected (e.g., network segregation, network segmentation).","checks_status": {"fail": 3,"pass": 7,"total": 17,"manual": 0}},"ac_6": {"name": "PR.AC-6","checks": {"redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac_6","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Identities are proofed and bound to credentials and asserted in interactions.","checks_status": {"fail": 1,"pass": 1,"total": 4,"manual": 0}},"ac_7": {"name": "PR.AC-7","checks": {"iam_root_mfa_enabled": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ac_7","Section": "Protect (PR)","Service": "iam","SubGroup": null,"SubSection": "Identity Management and Access Control (PR.AC)"}],"description": "Users, devices, and other assets are authenticated (e.g., single-factor, multi-factor) commensurate with the risk of the transaction (e.g., individualsā security and privacy risks and other organizational risks).","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"ae_1": {"name": "DE.AE-1","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL","s3_bucket_server_access_logging_enabled": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ae_1","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Anomalies and Events (DE.AE)"}],"description": "A baseline of network operations and expected data flows for users and systems is established and managed.","checks_status": {"fail": 7,"pass": 3,"total": 13,"manual": 0}},"ae_2": {"name": "DE.AE-2","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ae_2","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Anomalies and Events (DE.AE)"}],"description": "Detected events are analyzed to understand attack targets and methods.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ae_3": {"name": "DE.AE-3","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ae_3","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Anomalies and Events (DE.AE)"}],"description": "Event data are collected and correlated from multiple sources and sensors.","checks_status": {"fail": 5,"pass": 2,"total": 11,"manual": 0}},"ae_4": {"name": "DE.AE-4","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ae_4","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Anomalies and Events (DE.AE)"}],"description": "Impact of events is determined.","checks_status": {"fail": 4,"pass": 3,"total": 10,"manual": 0}},"ae_5": {"name": "DE.AE-5","checks": {"cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ae_5","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Anomalies and Events (DE.AE)"}],"description": "Incident alert thresholds are established.","checks_status": {"fail": 0,"pass": 0,"total": 4,"manual": 0}},"am_1": {"name": "ID.AM-1","checks": {"ec2_instance_managed_by_ssm": "FAIL","config_recorder_all_regions_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "am_1","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Asset Management (ID.AM)"}],"description": "Physical devices and systems within the organization are inventoried.","checks_status": {"fail": 1,"pass": 0,"total": 2,"manual": 0}},"am_2": {"name": "ID.AM-2","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "am_2","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Asset Management (ID.AM)"}],"description": "Software platforms and applications within the organization are inventoried.","checks_status": {"fail": 2,"pass": 0,"total": 2,"manual": 0}},"am_3": {"name": "ID.AM-3","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "am_3","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Asset Management (ID.AM)"}],"description": "Organizational communication and data flows are mapped.","checks_status": {"fail": 4,"pass": 2,"total": 8,"manual": 0}},"am_5": {"name": "ID.AM-5","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "am_5","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Asset Management (ID.AM)"}],"description": "Resources (e.g., hardware, devices, data, time, personnel, and software) are prioritized based on their classification, criticality, and business value.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"am_6": {"name": "ID.AM-6","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "am_6","Section": "Identify (ID)","Service": "iam","SubGroup": null,"SubSection": "Asset Management (ID.AM)"}],"description": "Cybersecurity roles and responsibilities for the entire workforce and third-party stakeholders (e.g., suppliers, customers, partners) are established.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"an_2": {"name": "RS.AN-2","checks": {"guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "an_2","Section": "Respond (RS)","Service": "guardduty","SubGroup": null,"SubSection": "Analysis (RS.AN)"}],"description": "The impact of the incident is understood.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"be_5": {"name": "ID.BE-5","checks": {"rds_instance_multi_az": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "be_5","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Business Environment (ID.BE)"}],"description": "Resilience requirements to support delivery of critical services are established for all operating states (e.g. under duress/attack, during recovery, normal operations)","checks_status": {"fail": 3,"pass": 1,"total": 4,"manual": 0}},"cm_1": {"name": "DE.CM-1","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_1","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "The network is monitored to detect potential cybersecurity events.","checks_status": {"fail": 4,"pass": 4,"total": 11,"manual": 0}},"cm_2": {"name": "DE.CM-2","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","config_recorder_all_regions_enabled": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_2","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "The physical environment is monitored to detect potential cybersecurity events.","checks_status": {"fail": 2,"pass": 3,"total": 20,"manual": 0}},"cm_3": {"name": "DE.CM-3","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_multi_region_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_3","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "Personnel activity is monitored to detect potential cybersecurity events.","checks_status": {"fail": 1,"pass": 3,"total": 7,"manual": 0}},"cm_4": {"name": "DE.CM-4","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "cm_4","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "Malicious code is detected.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"cm_5": {"name": "DE.CM-5","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_waf_acl_attached": "FAIL","ec2_instance_imdsv2_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_5","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "Unauthorized mobile code is detected.","checks_status": {"fail": 3,"pass": 3,"total": 10,"manual": 0}},"cm_6": {"name": "DE.CM-6","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","cloudtrail_multi_region_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_6","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "External service provider activity is monitored to detect potential cybersecurity events.","checks_status": {"fail": 1,"pass": 3,"total": 7,"manual": 0}},"cm_7": {"name": "DE.CM-7","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm_7","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Security Continuous Monitoring (DE.CM)"}],"description": "Monitoring for unauthorized personnel, connections, devices, and software is performed.","checks_status": {"fail": 4,"pass": 4,"total": 11,"manual": 0}},"cp_4": {"name": "DE.DP-4","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_waf_acl_attached": "FAIL","ec2_instance_imdsv2_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cp_4","Section": "Detect (DE)","Service": "aws","SubGroup": null,"SubSection": "Detection Processes (DE.DP)"}],"description": "Event detection information is communicated.","checks_status": {"fail": 3,"pass": 3,"total": 10,"manual": 0}},"cp_5": {"name": "DE.DP-5","checks": {"ec2_instance_imdsv2_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "cp_5","Section": "Detect (DE)","Service": "ec2","SubGroup": null,"SubSection": "Detection Processes (DE.DP)"}],"description": "Detection processes are continuously improved.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"ds_1": {"name": "PR.DS-1","checks": {"ec2_ebs_volume_encryption": "PASS","s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","sns_topics_kms_encryption_at_rest_enabled": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_1","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Data-at-rest is protected.","checks_status": {"fail": 5,"pass": 2,"total": 9,"manual": 0}},"ds_2": {"name": "PR.DS-2","checks": {"elb_ssl_listeners": "FAIL","acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_2","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Data-in-transit is protected.","checks_status": {"fail": 2,"pass": 1,"total": 4,"manual": 0}},"ds_3": {"name": "PR.DS-3","checks": {"ec2_elastic_ip_unassigned": "FAIL","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_3","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Assets are formally managed throughout removal, transfers, and disposition.","checks_status": {"fail": 3,"pass": 0,"total": 3,"manual": 0}},"ds_4": {"name": "PR.DS-4","checks": {"rds_instance_multi_az": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","rds_instance_enhanced_monitoring_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_4","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Adequate capacity to ensure availability is maintained.","checks_status": {"fail": 4,"pass": 1,"total": 5,"manual": 0}},"ds_5": {"name": "PR.DS-5","checks": {"elb_logging_enabled": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"cloudtrail_multi_region_enabled": "PASS","s3_bucket_policy_public_write_access": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"s3_account_level_public_access_blocks": null,"cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_5","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Protections against data leaks are implemented.","checks_status": {"fail": 4,"pass": 7,"total": 19,"manual": 0}},"ds_6": {"name": "PR.DS-6","checks": {"cloudtrail_log_file_validation_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_6","Section": "Protect (PR)","Service": "cloudtrail","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Integrity checking mechanisms are used to verify software, firmware, and information integrity.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"ds_7": {"name": "PR.DS-7","checks": {"elbv2_deletion_protection": "FAIL","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","ec2_instance_older_than_specific_days": "FAIL","cloudtrail_log_file_validation_enabled": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_7","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "The development and testing environment(s) are separate from the production environment.","checks_status": {"fail": 5,"pass": 1,"total": 6,"manual": 0}},"ds_8": {"name": "PR.DS-8","checks": {"securityhub_enabled": "PASS","ec2_instance_managed_by_ssm": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ds_8","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Data Security (PR.DS)"}],"description": "Integrity checking mechanisms are used to verify hardware integrity.","checks_status": {"fail": 1,"pass": 1,"total": 2,"manual": 0}},"ip_1": {"name": "PR.IP-1","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","ec2_instance_older_than_specific_days": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_1","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "A baseline configuration of information technology/industrial control systems is created and maintained incorporating security principles (e.g. concept of least functionality).","checks_status": {"fail": 3,"pass": 0,"total": 3,"manual": 0}},"ip_2": {"name": "PR.IP-2","checks": {"ec2_instance_managed_by_ssm": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_2","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "A System Development Life Cycle to manage systems is implemented.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"ip_3": {"name": "PR.IP-3","checks": {"elbv2_deletion_protection": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_3","Section": "Protect (PR)","Service": "elb","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "Configuration change control processes are in place.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"ip_4": {"name": "PR.IP-4","checks": {"rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_4","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "Backups of information are conducted, maintained, and tested periodically.","checks_status": {"fail": 1,"pass": 1,"total": 3,"manual": 0}},"ip_7": {"name": "PR.IP-7","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "ip_7","Section": "Protect (PR)","Service": "ec2","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "Protection processes are improved.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ip_8": {"name": "PR.IP-8","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"eks_cluster_not_publicly_accessible": null,"s3_bucket_policy_public_write_access": "PASS","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_8","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "Effectiveness of protection technologies is shared.","checks_status": {"fail": 1,"pass": 4,"total": 13,"manual": 0}},"ip_9": {"name": "PR.IP-9","checks": {"rds_instance_multi_az": "FAIL","efs_have_backup_enabled": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_9","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "Response plans (Incident Response and Business Continuity) and recovery plans (Incident Recovery and Disaster Recovery) are in place and managed.","checks_status": {"fail": 4,"pass": 1,"total": 10,"manual": 0}},"ma_2": {"name": "PR.MA-2","checks": {"cloudtrail_multi_region_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ma_2","Section": "Protect (PR)","Service": "cloudtrail","SubGroup": null,"SubSection": "Maintenance (PR.MA)"}],"description": "Remote maintenance of organizational assets is approved, logged, and performed in a manner that prevents unauthorized access.","checks_status": {"fail": 0,"pass": 1,"total": 2,"manual": 0}},"mi_3": {"name": "RS.MI-3","checks": {"guardduty_no_high_severity_findings": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "mi_3","Section": "Respond (RS)","Service": "guardduty","SubGroup": null,"SubSection": "Mitigation (RS.MI)"}],"description": "Newly identified vulnerabilities are mitigated or documented as accepted risks.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"pt_1": {"name": "PR.PT-1","checks": {"elb_logging_enabled": "FAIL","elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_cloudwatch_logging_enabled": "FAIL","s3_bucket_server_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "pt_1","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Protective Technology (PR.PT)"}],"description": "Audit/log records are determined, documented, implemented, and reviewed in accordance with policy.","checks_status": {"fail": 5,"pass": 2,"total": 8,"manual": 0}},"pt_3": {"name": "PR.PT-3","checks": {"iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","s3_account_level_public_access_blocks": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "pt_3","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Protective Technology (PR.PT)"}],"description": "The principle of least functionality is incorporated by configuring systems to provide only essential capabilities.","checks_status": {"fail": 0,"pass": 3,"total": 11,"manual": 0}},"pt_4": {"name": "PR.PT-4","checks": {"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"ec2_networkacl_allow_ingress_any_port": "FAIL","awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "pt_4","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Protective Technology (PR.PT)"}],"description": "Communications and control networks are protected.","checks_status": {"fail": 1,"pass": 3,"total": 6,"manual": 0}},"pt_5": {"name": "PR.PT-5","checks": {"rds_instance_multi_az": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "pt_5","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Protective Technology (PR.PT)"}],"description": "Mechanisms (e.g., failsafe, load balancing, hot swap) are implemented to achieve resilience requirements in normal and adverse situations.","checks_status": {"fail": 3,"pass": 1,"total": 4,"manual": 0}},"ra_1": {"name": "ID.RA-1","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ra_1","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Risk Assessment (ID.RA)"}],"description": "Asset vulnerabilities are identified and documented.","checks_status": {"fail": 1,"pass": 2,"total": 3,"manual": 0}},"ra_2": {"name": "ID.RA-2","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ra_2","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Risk Assessment (ID.RA)"}],"description": "Cyber threat intelligence is received from information sharing forums and sources.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ra_3": {"name": "ID.RA-3","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "ra_3","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Risk Assessment (ID.RA)"}],"description": "Threats, both internal and external, are identified and documented.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ra_5": {"name": "ID.RA-5","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","config_recorder_all_regions_enabled": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null,"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ra_5","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Risk Assessment (ID.RA)"}],"description": "Threats, vulnerabilities, likelihoods, and impacts are used to determine risk.","checks_status": {"fail": 2,"pass": 3,"total": 20,"manual": 0}},"rp_1": {"name": "RS.RP-1","checks": {"rds_instance_multi_az": "FAIL","efs_have_backup_enabled": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "rp_1","Section": "Respond (RS)","Service": "aws","SubGroup": null,"SubSection": "Response Planning (RS.RP)"}],"description": "Response plan is executed during or after an incident.","checks_status": {"fail": 4,"pass": 1,"total": 11,"manual": 0}},"sc_4": {"name": "ID.SC-4","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_imdsv2_enabled": "PASS","config_recorder_all_regions_enabled": null,"cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudwatch_log_metric_filter_root_usage": null,"rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_log_metric_filter_policy_changes": null,"cloudwatch_log_metric_filter_sign_in_without_mfa": null,"cloudwatch_log_metric_filter_security_group_changes": null,"cloudwatch_log_metric_filter_unauthorized_api_calls": null,"cloudwatch_log_metric_filter_authentication_failures": null,"cloudwatch_log_metric_filter_for_s3_bucket_policy_changes": null,"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null,"cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled": null,"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc_4","Section": "Identify (ID)","Service": "aws","SubGroup": null,"SubSection": "Supply Chain Risk Management (ID.SC)"}],"description": "Suppliers and third-party partners are routinely assessed using audits, test results, or other forms of evaluations to confirm they are meeting their contractual obligations.","checks_status": {"fail": 2,"pass": 3,"total": 16,"manual": 0}},"ip_12": {"name": "PR.IP-12","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL","config_recorder_all_regions_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ip_12","Section": "Protect (PR)","Service": "aws","SubGroup": null,"SubSection": "Information Protection Processes and Procedures (PR.IP)"}],"description": "A vulnerability management plan is developed and implemented.","checks_status": {"fail": 2,"pass": 0,"total": 4,"manual": 0}}},"requirements_passed": 11,"requirements_failed": 42,"requirements_manual": 3,"total_requirements": 56,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "23ef3629-e1cd-4f16-af98-ab0daaff257e","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "fedramp_low_revision_4_aws","framework": "FedRAMP-Low-Revision-4","version": "","description": "The Federal Risk and Authorization Management Program (FedRAMP) was established in 2011. It provides a cost-effective, risk-based approach for the adoption and use of cloud services by the U.S. federal government. FedRAMP empowers federal agencies to use modern cloud technologies, with an emphasis on the security and protection of federal information.","region": "eu-west-1","requirements": {"ac-2": {"name": "Account Management (AC-2)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","iam_root_mfa_enabled": null,"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_root_hardware_mfa_enabled": null,"iam_rotate_access_key_90_days": null,"iam_user_hardware_mfa_enabled": null,"iam_user_console_access_unused": null,"redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","iam_user_mfa_enabled_console_access": null,"cloudtrail_s3_dataevents_read_enabled": null,"iam_password_policy_minimum_length_14": null,"cloudtrail_log_file_validation_enabled": "FAIL","cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL","iam_policy_attached_only_to_group_or_roles": null,"iam_inline_policy_no_administrative_privileges": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"iam_aws_attached_policy_no_administrative_privileges": null,"opensearch_service_domains_cloudwatch_logging_enabled": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac-2","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Manage system accounts, group memberships, privileges, workflow, notifications, deactivations, and authorizations.","checks_status": {"fail": 3,"pass": 4,"total": 26,"manual": 0}},"ac-3": {"name": "Account Management (AC-3)","checks": {"ec2_instance_public_ip": "FAIL","iam_no_root_access_key": null,"ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"iam_user_accesskey_unused": null,"ec2_instance_imdsv2_enabled": "PASS","rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","iam_user_console_access_unused": null,"redshift_cluster_public_access": null,"s3_bucket_policy_public_write_access": "PASS","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","iam_policy_attached_only_to_group_or_roles": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null,"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac-3","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system enforces approved authorizations for logical access to information and system resources in accordance with applicable access control policies.","checks_status": {"fail": 1,"pass": 6,"total": 20,"manual": 0}},"au-2": {"name": "Audit Events (AU-2)","checks": {"elbv2_logging_enabled": "FAIL","vpc_flow_logs_enabled": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","apigateway_restapi_logging_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_log_file_validation_enabled": "FAIL","cloudtrail_s3_dataevents_write_enabled": null,"s3_bucket_server_access_logging_enabled": "FAIL","rds_instance_integration_cloudwatch_logs": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au-2","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization: a. Determines that the information system is capable of auditing the following events: [Assignment: organization-defined auditable events]; b. Coordinates the security audit function with other organizational entities requiring audit- related information to enhance mutual support and to help guide the selection of auditable events; c. Provides a rationale for why the auditable events are deemed to be adequate support after- the-fact investigations of security incidents","checks_status": {"fail": 5,"pass": 2,"total": 11,"manual": 0}},"au-9": {"name": "Protection of Audit Information (AU-9)","checks": {"s3_bucket_object_versioning": "FAIL","cloudtrail_kms_encryption_enabled": "FAIL","cloudtrail_log_file_validation_enabled": "FAIL","cloudwatch_log_group_kms_encryption_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au-9","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects audit information and audit tools from unauthorized access, modification, and deletion.","checks_status": {"fail": 4,"pass": 0,"total": 4,"manual": 0}},"ca-7": {"name": "Continuous Monitoring (CA-7)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","elbv2_waf_acl_attached": "FAIL","ec2_instance_imdsv2_enabled": "PASS","redshift_cluster_audit_logging": null,"cloudtrail_multi_region_enabled": "PASS","cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null,"rds_instance_enhanced_monitoring_enabled": "FAIL","cloudwatch_changes_to_network_acls_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ca-7","Section": "Security Assessment And Authorization (CA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Continuously monitor configuration management processes. Determine security impact, environment and operational risks.","checks_status": {"fail": 2,"pass": 4,"total": 11,"manual": 0}},"cm-2": {"name": "Baseline Configuration (CM-2)","checks": {"ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"elbv2_deletion_protection": "FAIL","rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"ssm_managed_compliant_patching": "FAIL","apigateway_restapi_waf_acl_attached": "FAIL","s3_bucket_policy_public_write_access": "PASS","ec2_instance_older_than_specific_days": "FAIL","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm-2","Section": "Configuration Management (CM)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization develops, documents, and maintains under configuration control, a current baseline configuration of the information system.","checks_status": {"fail": 7,"pass": 6,"total": 21,"manual": 0}},"cm-8": {"name": "Information System Component Inventory (CM-8)","checks": {"guardduty_is_enabled": "PASS","ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cm-8","Section": "Configuration Management (CM)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization develops and documents an inventory of information system components that accurately reflects the current information system, includes all components within the authorization boundary of the information system, is at the level of granularity deemed necessary for tracking and reporting and reviews and updates the information system component inventory.","checks_status": {"fail": 2,"pass": 1,"total": 4,"manual": 0}},"cp-9": {"name": "Information System Backup (CP-9)","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cp-9","Section": "Contingency Planning (CP)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization conducts backups of user-level information, system-level information and information system documentation including security-related documentation contained in the information system and protects the confidentiality, integrity, and availability of backup information at storage locations.","checks_status": {"fail": 2,"pass": 1,"total": 7,"manual": 0}},"ia-2": {"name": "Identification and Authentication (Organizational users) (IA-2)","checks": {"iam_root_mfa_enabled": null,"iam_no_root_access_key": null,"iam_root_hardware_mfa_enabled": null,"iam_user_mfa_enabled_console_access": null,"iam_password_policy_minimum_length_14": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "ia-2","Section": "Identification and Authentication (IA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system uniquely identifies and authenticates organizational users (or processes acting on behalf of organizational users).","checks_status": {"fail": 0,"pass": 0,"total": 6,"manual": 0}},"ir-4": {"name": "Incident Handling (IR-4)","checks": {"securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","guardduty_no_high_severity_findings": "FAIL","cloudwatch_changes_to_vpcs_alarm_configured": null,"cloudwatch_changes_to_network_acls_alarm_configured": null,"cloudwatch_changes_to_network_gateways_alarm_configured": null,"cloudwatch_changes_to_network_route_tables_alarm_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ir-4","Section": "Incident Response (IR)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization implements an incident handling capability for security incidents that includes preparation, detection and analysis, containment, eradication, and recovery, coordinates incident handling activities with contingency planning activities and incorporates lessons learned from ongoing incident handling activities into incident response procedures, training, and testing, and implements the resulting changes accordingly.","checks_status": {"fail": 1,"pass": 2,"total": 7,"manual": 0}},"sa-3": {"name": "System Development Life Cycle (SA-3)","checks": {"ec2_instance_managed_by_ssm": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sa-3","Section": "System and Services Acquisition (SA)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization manages the information system using organization-defined system development life cycle, defines and documents information security roles and responsibilities throughout the system development life cycle, identifies individuals having information security roles and responsibilities and integrates the organizational information security risk management process into system development life cycle activities.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"sc-5": {"name": "Denial Of Service Protection (SC-5)","checks": {"guardduty_is_enabled": "PASS","rds_instance_multi_az": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"rds_instance_deletion_protection": "FAIL","redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc-5","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system protects against or limits the effects of the following types of denial of service attacks: [Assignment: organization-defined types of denial of service attacks or references to sources for such information] by employing [Assignment: organization-defined security safeguards].","checks_status": {"fail": 4,"pass": 2,"total": 8,"manual": 0}},"sc-7": {"name": "Boundary Protection (SC-7)","checks": {"elb_ssl_listeners": "FAIL","ec2_instance_public_ip": "FAIL","elbv2_waf_acl_attached": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"s3_bucket_secure_transport_policy": "FAIL","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","opensearch_service_domains_node_to_node_encryption_enabled": null,"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc-7","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system: a. Monitors and controls communications at the external boundary of the system and at key internal boundaries within the system; b. Implements subnetworks for publicly accessible system components that are [Selection: physically; logically] separated from internal organizational networks; and c. Connects to external networks or information systems only through managed interfaces consisting of boundary protection devices arranged in accordance with an organizational security architecture.","checks_status": {"fail": 6,"pass": 6,"total": 21,"manual": 0}},"ac-17": {"name": "Remote Access (AC-17)","checks": {"elb_ssl_listeners": "FAIL","securityhub_enabled": "PASS","guardduty_is_enabled": "PASS","ec2_instance_public_ip": "FAIL","ec2_ebs_public_snapshot": "PASS","s3_bucket_public_access": null,"rds_snapshots_public_access": "PASS","awslambda_function_url_public": null,"rds_instance_no_public_access": "PASS","redshift_cluster_public_access": null,"acm_certificates_expiration_check": "PASS","s3_bucket_secure_transport_policy": "FAIL","s3_bucket_policy_public_write_access": "PASS","ec2_networkacl_allow_ingress_any_port": "FAIL","emr_cluster_master_nodes_no_public_ip": null,"s3_account_level_public_access_blocks": null,"awslambda_function_not_publicly_accessible": "PASS","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ac-17","Section": "Access Control (AC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Authorize remote access systems prior to connection. Enforce remote connection requirements to information systems.","checks_status": {"fail": 5,"pass": 9,"total": 21,"manual": 0}},"au-11": {"name": "Audit Record Retention (AU-11)","checks": {"cloudwatch_log_group_retention_policy_specific_days_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "au-11","Section": "Audit and Accountability (AU)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization retains audit records for at least 90 days to provide support for after-the-fact investigations of security incidents and to meet regulatory and organizational information retention requirements.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"cp-10": {"name": "Information System Recovery And Reconstitution (CP-10)","checks": {"rds_instance_multi_az": "FAIL","efs_have_backup_enabled": "FAIL","elbv2_deletion_protection": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cp-10","Section": "Contingency Planning (CP)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization provides for the recovery and reconstitution of the information system to a known state after a disruption, compromise, or failure.","checks_status": {"fail": 4,"pass": 1,"total": 9,"manual": 0}},"sc-12": {"name": "Cryptographic Key Establishment And Management (SC-12)","checks": {"kms_cmk_rotation_enabled": null,"acm_certificates_expiration_check": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "sc-12","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The organization establishes and manages cryptographic keys for required cryptography employed within the information system in accordance with [Assignment: organization-defined requirements for key generation, distribution, storage, access, and destruction].","checks_status": {"fail": 0,"pass": 1,"total": 2,"manual": 0}},"sc-13": {"name": "Use of Cryptography (SC-13)","checks": {"s3_bucket_default_encryption": "PASS","sns_topics_kms_encryption_at_rest_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"sagemaker_training_jobs_volume_and_output_encryption_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "sc-13","Section": "System and Communications Protection (SC)","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The information system implements FIPS-validated or NSA-approved cryptography in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards.","checks_status": {"fail": 1,"pass": 1,"total": 4,"manual": 0}}},"requirements_passed": 2,"requirements_failed": 16,"requirements_manual": 0,"total_requirements": 18,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "2d3bdafb-2503-4e04-a107-bdda7c4163ba","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "aws_audit_manager_control_tower_guardrails_aws","framework": "AWS-Audit-Manager-Control-Tower-Guardrails","version": "","description": "AWS Control Tower is a management and governance service that you can use to navigate through the setup process and governance requirements that are involved in creating a multi-account AWS environment.","region": "eu-west-1","requirements": {"1.0.1": {"name": "Disallow launch of EC2 instance types that are not EBS-optimized","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "1.0.1","Section": "EBS checks","Service": "ebs","SubGroup": null,"SubSection": null}],"description": "Checks whether EBS optimization is enabled for your EC2 instances that can be EBS-optimized","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.0.2": {"name": "Disallow EBS volumes that are unattached to an EC2 instance","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "1.0.2","Section": "EBS checks","Service": "ebs","SubGroup": null,"SubSection": null}],"description": "Checks whether EBS volumes are attached to EC2 instances","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"1.0.3": {"name": "Enable encryption for EBS volumes attached to EC2 instances","checks": {"ec2_ebs_default_encryption": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "1.0.3","Section": "EBS checks","Service": "ebs","SubGroup": null,"SubSection": null}],"description": "Checks whether EBS volumes that are in an attached state are encrypted","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"2.0.1": {"name": "Disallow internet connection through RDP","checks": {"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "2.0.1","Section": "Disallow Internet Connection","Service": "vpc","SubGroup": null,"SubSection": null}],"description": "Checks whether security groups that are in use disallow unrestricted incoming TCP traffic to the specified","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"2.0.2": {"name": "Disallow internet connection through SSH","checks": {"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "2.0.2","Section": "Disallow Internet Connection","Service": "vpc","SubGroup": null,"SubSection": null}],"description": "Checks whether security groups that are in use disallow unrestricted incoming SSH traffic.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"3.0.1": {"name": "Disallow access to IAM users without MFA","checks": {"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3.0.1","Section": "Multi-Factor Authentication","Service": "iam","SubGroup": null,"SubSection": null}],"description": "Checks whether the AWS Identity and Access Management users have multi-factor authentication (MFA) enabled.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"3.0.2": {"name": "Disallow console access to IAM users without MFA","checks": {"iam_user_mfa_enabled_console_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3.0.2","Section": "Multi-Factor Authentication","Service": "iam","SubGroup": null,"SubSection": null}],"description": "Checks whether AWS Multi-Factor Authentication (MFA) is enabled for all AWS Identity and Access Management (IAM) users that use a console password.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"3.0.3": {"name": "Enable MFA for the root user","checks": {"iam_root_mfa_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "3.0.3","Section": "Multi-Factor Authentication","Service": "iam","SubGroup": null,"SubSection": null}],"description": "Checks whether the root user of your AWS account requires multi-factor authentication for console sign-in.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.0.1": {"name": "Disallow public access to RDS database instances","checks": {"rds_instance_no_public_access": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.0.1","Section": "Disallow Public Access","Service": "rds","SubGroup": null,"SubSection": null}],"description": "Checks whether the Amazon Relational Database Service (RDS) instances are not publicly accessible. The rule is non-compliant if the publiclyAccessible field is true in the instance configuration item.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"4.0.2": {"name": "Disallow public access to RDS database snapshots","checks": {"rds_snapshots_public_access": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.0.2","Section": "Disallow Public Access","Service": "rds","SubGroup": null,"SubSection": null}],"description": "Checks if Amazon Relational Database Service (Amazon RDS) snapshots are public. The rule is non-compliant if any existing and new Amazon RDS snapshots are public.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"4.1.1": {"name": "Disallow public read access to S3 buckets","checks": {"rds_instance_no_public_access": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.1.1","Section": "Disallow Public Access","Service": "s3","SubGroup": null,"SubSection": null}],"description": "Checks that your S3 buckets do not allow public read access.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"4.1.2": {"name": "Disallow public write access to S3 buckets","checks": {"s3_bucket_policy_public_write_access": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.1.2","Section": "Disallow Public Access","Service": "s3","SubGroup": null,"SubSection": null}],"description": "Checks that your S3 buckets do not allow public write access.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"5.0.1": {"name": "Disallow RDS database instances that are not storage encrypted ","checks": {"rds_instance_storage_encrypted": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "5.0.1","Section": "Disallow Instances","Service": "rds","SubGroup": null,"SubSection": null}],"description": "Checks whether storage encryption is enabled for your RDS DB instances.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"5.1.1": {"name": "Disallow S3 buckets that are not versioning enabled","checks": {"s3_bucket_object_versioning": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "5.1.1","Section": "Disallow Instances","Service": "s3","SubGroup": null,"SubSection": null}],"description": "Checks whether versioning is enabled for your S3 buckets.","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}}},"requirements_passed": 10,"requirements_failed": 2,"requirements_manual": 2,"total_requirements": 14,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "3477e5c1-467e-4fb1-9b4b-1c2bc8fcd03e","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "pci_3.2.1_aws","framework": "PCI","version": "3.2.1","description": "The Payment Card Industry Data Security Standard (PCI DSS) is a proprietary information security standard. It's administered by the PCI Security Standards Council, which was founded by American Express, Discover Financial Services, JCB International, MasterCard Worldwide, and Visa Inc. PCI DSS applies to entities that store, process, or transmit cardholder data (CHD) or sensitive authentication data (SAD). This includes, but isn't limited to, merchants, processors, acquirers, issuers, and service providers. The PCI DSS is mandated by the card brands and administered by the Payment Card Industry Security Standards Council.","region": "eu-west-1","requirements": {"cw": {"name": "CloudWatch","checks": {"cloudwatch_log_metric_filter_root_usage": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "cw","Section": null,"Service": "cloudwatch","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring CloudWatch resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"s3": {"name": "S3","checks": {"s3_bucket_public_access": null,"s3_bucket_default_encryption": "PASS","s3_bucket_secure_transport_policy": "FAIL","s3_bucket_policy_public_write_access": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "s3","Section": null,"Service": "s3","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS S3 resources and options.","checks_status": {"fail": 1,"pass": 2,"total": 5,"manual": 0}},"dms": {"name": "DMS","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "dms","Section": null,"Service": "dms","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS DMS resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"ec2": {"name": "EC2","checks": {"vpc_flow_logs_enabled": "FAIL","ec2_ebs_public_snapshot": "PASS","ec2_elastic_ip_unassigned": "FAIL","ec2_securitygroup_default_restrict_traffic": "FAIL","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22": "PASS","ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389": "PASS"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ec2","Section": null,"Service": "ec2","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring EC2 resources and options.","checks_status": {"fail": 3,"pass": 3,"total": 6,"manual": 0}},"iam": {"name": "IAM","checks": {"iam_root_mfa_enabled": null,"iam_no_root_access_key": null,"iam_user_accesskey_unused": null,"iam_password_policy_number": null,"iam_password_policy_symbol": null,"iam_password_policy_lowercase": null,"iam_password_policy_uppercase": null,"iam_root_hardware_mfa_enabled": null,"iam_user_console_access_unused": null,"iam_user_mfa_enabled_console_access": null,"iam_password_policy_minimum_length_14": null,"iam_inline_policy_no_administrative_privileges": null,"iam_aws_attached_policy_no_administrative_privileges": null,"iam_customer_attached_policy_no_administrative_privileges": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "iam","Section": null,"Service": "iam","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS IAM resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 15,"manual": 0}},"kms": {"name": "KMS","checks": {"kms_cmk_rotation_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "kms","Section": null,"Service": "kms","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS KMS resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"rds": {"name": "RDS","checks": {"rds_snapshots_public_access": "PASS","rds_instance_no_public_access": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "rds","Section": null,"Service": "rds","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS RDS resources and options.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"ssm": {"name": "SSM","checks": {"ec2_instance_managed_by_ssm": "FAIL","ssm_managed_compliant_patching": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "ssm","Section": null,"Service": "ssm","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS SSM resources and options.","checks_status": {"fail": 2,"pass": 0,"total": 3,"manual": 0}},"elbv2": {"name": "ELBV2","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "elbv2","Section": null,"Service": "elbv2","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring Elastic Load Balancer resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"config": {"name": "Config","checks": {"config_recorder_all_regions_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "config","Section": null,"Service": "config","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS Config.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"lambda": {"name": "Lambda","checks": {"awslambda_function_url_public": null,"awslambda_function_not_publicly_accessible": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "lambda","Section": null,"Service": "lambda","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring Lambda resources and options.","checks_status": {"fail": 0,"pass": 1,"total": 2,"manual": 0}},"redshift": {"name": "Redshift","checks": {"redshift_cluster_public_access": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "redshift","Section": null,"Service": "redshift","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS Redshift resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"codebuild": {"name": "CodeBuild","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "codebuild","Section": null,"Service": "codebuild","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring CodeBuild resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"guardduty": {"name": "GuardDuty","checks": {"guardduty_is_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "guardduty","Section": null,"Service": "guardduty","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS GuardDuty resources and options.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"sagemaker": {"name": "SageMaker","checks": {"sagemaker_notebook_instance_without_direct_internet_access_configured": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "sagemaker","Section": null,"Service": "sagemaker","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring AWS Sagemaker resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"cloudtrail": {"name": "CloudTrail","checks": {"cloudtrail_multi_region_enabled": "PASS","cloudtrail_kms_encryption_enabled": "FAIL","cloudtrail_cloudwatch_logging_enabled": "FAIL","cloudtrail_log_file_validation_enabled": "FAIL"},"status": "FAIL","attributes": [{"Type": null,"ItemId": "cloudtrail","Section": null,"Service": "cloudtrail","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring CloudTrail resources and options.","checks_status": {"fail": 3,"pass": 1,"total": 4,"manual": 0}},"opensearch": {"name": "OpenSearch","checks": {"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "opensearch","Section": null,"Service": "opensearch","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring OpenSearch resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"autoscaling": {"name": "Auto Scaling","checks": {},"status": "PASS","attributes": [{"Type": null,"ItemId": "autoscaling","Section": null,"Service": "autoscaling","SubGroup": null,"SubSection": null}],"description": "This control checks whether your Auto Scaling groups that are associated with a load balancer are using Elastic Load Balancing health checks. PCI DSS does not require load balancing or highly available configurations. However, this check aligns with AWS best practices.","checks_status": {"fail": 0,"pass": 0,"total": 0,"manual": 0}},"elasticsearch": {"name": "Elasticsearch","checks": {"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "elasticsearch","Section": null,"Service": "elasticsearch","SubGroup": null,"SubSection": null}],"description": "This section contains recommendations for configuring Elasticsearch resources and options.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}}},"requirements_passed": 11,"requirements_failed": 4,"requirements_manual": 4,"total_requirements": 19,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "34f5d2fe-fe37-4143-81ce-fdf21d9a9826","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "gxp_eu_annex_11_aws","framework": "GxP-EU-Annex-11","version": "","description": "The GxP EU Annex 11 framework is the European equivalent to the FDA 21 CFR part 11 framework in the United States. This annex applies to all forms of computerized systems that are used as part of Good Manufacturing Practices (GMP) regulated activities. A computerized system is a set of software and hardware components that together fulfill certain functionalities. The application should be validated and IT infrastructure should be qualified. Where a computerized system replaces a manual operation, there should be no resultant decrease in product quality, process control, or quality assurance. There should be no increase in the overall risk of the process.","region": "eu-west-1","requirements": {"5-data": {"name": "5 Data","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "5-data","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Computerised systems exchanging data electronically with other systems should include appropriate built-in checks for the correct and secure entry and processing of data, in order to minimize the risks.","checks_status": {"fail": 2,"pass": 1,"total": 8,"manual": 0}},"17-archiving": {"name": "17 Archiving","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "17-archiving","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Data may be archived. This data should be checked for accessibility, readability and integrity. If relevant changes are to be made to the system (e.g. computer equipment or programs), then the ability to retrieve the data should be ensured and tested.","checks_status": {"fail": 2,"pass": 1,"total": 9,"manual": 0}},"9-audit-trails": {"name": "9 Audit Trails","checks": {"cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "9-audit-trails","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Consideration should be given, based on a risk assessment, to building into the system the creation of a record of all GMP-relevant changes and deletions (a system generated 'audit trail'). For change or deletion of GMP-relevant data the reason should be documented. Audit trails need to be available and convertible to a generally intelligible form and regularly reviewed.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"1-risk-management": {"name": "1 Risk Management","checks": {"securityhub_enabled": "PASS","cloudtrail_multi_region_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "1-risk-management","Section": "General","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Risk management should be applied throughout the lifecycle of the computerised system taking into account patient safety, data integrity and product quality. As part of a risk management system, decisions on the extent of validation and data integrity controls should be based on a justified and documented risk assessment of the computerised system.","checks_status": {"fail": 0,"pass": 2,"total": 2,"manual": 0}},"16-business-continuity": {"name": "16 Business Continuity","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "16-business-continuity","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "For the availability of computerised systems supporting critical processes, provisions should be made to ensure continuity of support for those processes in the event of a system breakdown (e.g. a manual or alternative system). The time required to bring the alternative arrangements into use should be based on risk and appropriate for a particular system and the business process it supports. These arrangements should be adequately documented and tested.","checks_status": {"fail": 2,"pass": 1,"total": 9,"manual": 0}},"7.2-data-storage-backups": {"name": "7.2 Data Storage - Backups","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "7.2-data-storage-backups","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Regular back-ups of all relevant data should be done. Integrity and accuracy of backup data and the ability to restore the data should be checked during validation and monitored periodically.","checks_status": {"fail": 2,"pass": 1,"total": 8,"manual": 0}},"12.4-security-audit-trail": {"name": "12.4 Security - Audit Trail","checks": {"cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "12.4-security-audit-trail","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Management systems for data and for documents should be designed to record the identity of operators entering, changing, confirming or deleting data including date and time.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"8.2-printouts-data-changes": {"name": "8.2 Printouts - Data Changes","checks": {"cloudtrail_s3_dataevents_read_enabled": null,"cloudtrail_s3_dataevents_write_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "8.2-printouts-data-changes","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "For records supporting batch release it should be possible to generate printouts indicating if any of the data has been changed since the original entry.","checks_status": {"fail": 0,"pass": 0,"total": 2,"manual": 0}},"4.8-validation-data-transfer": {"name": "4.8 Validation - Data Transfer","checks": {"efs_have_backup_enabled": "FAIL","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"redshift_cluster_automated_snapshot": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "4.8-validation-data-transfer","Section": "Project Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "If data are transferred to another data format or system, validation should include checks that data are not altered in value and/or meaning during this migration process.","checks_status": {"fail": 2,"pass": 1,"total": 9,"manual": 0}},"4.5-validation-development-quality": {"name": "4.5 Validation - Development Quality","checks": {"config_recorder_all_regions_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.5-validation-development-quality","Section": "Project Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "The regulated user should take all reasonable steps, to ensure that the system has been developed in accordance with an appropriate quality management system. The supplier should be assessed appropriately.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.6-validation-quality-performance": {"name": "4.6 Validation - Quality and Performance","checks": {"config_recorder_all_regions_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.6-validation-quality-performance","Section": "Project Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "For the validation of bespoke or customised computerised systems there should be a process in place that ensures the formal assessment and reporting of quality and performance measures for all the life-cycle stages of the system.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"7.1-data-storage-damage-protection": {"name": "7.1 Data Storage - Damage Protection","checks": {"ec2_ebs_volume_encryption": "PASS","ec2_ebs_default_encryption": "PASS","rds_instance_backup_enabled": "PASS","s3_bucket_object_versioning": "FAIL","dynamodb_tables_pitr_enabled": null,"s3_bucket_default_encryption": "PASS","efs_encryption_at_rest_enabled": "FAIL","rds_instance_storage_encrypted": "FAIL","redshift_cluster_audit_logging": null,"cloudtrail_kms_encryption_enabled": "FAIL","redshift_cluster_automated_snapshot": null,"sns_topics_kms_encryption_at_rest_enabled": "FAIL","dynamodb_tables_kms_cmk_encryption_enabled": null,"cloudwatch_log_group_kms_encryption_enabled": "FAIL","sagemaker_notebook_instance_encryption_enabled": null,"dynamodb_accelerator_cluster_encryption_enabled": null,"eks_cluster_kms_cmk_encryption_in_secrets_enabled": null,"opensearch_service_domains_encryption_at_rest_enabled": null},"status": "FAIL","attributes": [{"Type": null,"ItemId": "7.1-data-storage-damage-protection","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Data should be secured by both physical and electronic means against damage. Stored data should be checked for accessibility, readability and accuracy. Access to data should be ensured throughout the retention period.","checks_status": {"fail": 6,"pass": 4,"total": 22,"manual": 0}},"10-change-and-configuration-management": {"name": "10 Change and Configuration Management","checks": {"config_recorder_all_regions_enabled": null},"status": "PASS","attributes": [{"Type": null,"ItemId": "10-change-and-configuration-management","Section": "Operational Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Any changes to a computerised system including system configurations should only be made in a controlled manner in accordance with a defined procedure.","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.2-validation-documentation-change-control": {"name": "4.2 Validation - Documentation Change Control","checks": {"cloudtrail_multi_region_enabled": "PASS"},"status": "PASS","attributes": [{"Type": null,"ItemId": "4.2-validation-documentation-change-control","Section": "Project Phase","Service": "aws","SubGroup": null,"SubSection": null}],"description": "Validation documentation should include change control records (if applicable) and reports on any deviations observed during the validation process.","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}}},"requirements_passed": 8,"requirements_failed": 6,"requirements_manual": 0,"total_requirements": 14,"scan": "0191e280-9d2f-71c8-9b18-487a23ba185e"}},{"model": "api.complianceoverview","pk": "376854be-93cd-44ab-a070-1e996b24184d","fields": {"tenant": "12646005-9067-4d2a-a098-8bb378604362","inserted_at": "2024-11-15T13:14:10.043Z","compliance_id": "cis_1.5_aws","framework": "CIS","version": "1.5","description": "The CIS Amazon Web Services Foundations Benchmark provides prescriptive guidance for configuring security options for a subset of Amazon Web Services with an emphasis on foundational, testable, and architecture agnostic settings.","region": "eu-west-1","requirements": {"1.1": {"name": "1.1","checks": {"account_maintain_current_contact_details": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/manage-account-payment.html#contact-info","Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.","DefaultValue": null,"AuditProcedure": "This activity can only be performed via the AWS Console, with a user who has permission to read and write Billing information (aws-portal:\\*Billing )1. Sign in to the AWS Management Console and open the `Billing and Cost Management` console at https://console.aws.amazon.com/billing/home#/. 2. On the navigation bar, choose your account name, and then choose `My Account`. 3. On the `Account Settings` page, review and verify the current details. 4. Under `Contact Information`, review and verify the current details.","ImpactStatement": "","AssessmentStatus": "Manual","RationaleStatement": "If an AWS account is observed to be behaving in a prohibited or suspicious manner, AWS will attempt to contact the account owner by email and phone using the contact details listed. If this is unsuccessful and the account behavior needs urgent mitigation, proactive measures may be taken, including throttling of traffic between the account exhibiting suspicious behavior and the AWS API endpoints and the Internet. This will result in impaired service to and from the account in question, so it is in both the customers' and AWS' best interests that prompt contact can be established. This is best achieved by setting AWS account contact details to point to resources which have multiple individuals as recipients, such as email aliases and PABX hunt groups.","RemediationProcedure": "This activity can only be performed via the AWS Console, with a user who has permission to read and write Billing information (aws-portal:\\*Billing ).1. Sign in to the AWS Management Console and open the `Billing and Cost Management` console at https://console.aws.amazon.com/billing/home#/. 2. On the navigation bar, choose your account name, and then choose `My Account`. 3. On the `Account Settings` page, next to `Account Settings`, choose `Edit`. 4. Next to the field that you need to update, choose `Edit`. 5. After you have entered your changes, choose `Save changes`. 6. After you have made your changes, choose `Done`. 7. To edit your contact information, under `Contact Information`, choose `Edit`. 8. For the fields that you want to change, type your updated information, and then choose `Update`.","AdditionalInformation": ""}],"description": "Maintain current contact details","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.2": {"name": "1.2","checks": {"account_security_contact_information_is_registered": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "","Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if security contact information is present:**From Console:**1. Click on your account name at the top right corner of the console 2. From the drop-down menu Click `My Account`3. Scroll down to the `Alternate Contacts` section 4. Ensure contact information is specified in the `Security` section","ImpactStatement": "","AssessmentStatus": "Manual","RationaleStatement": "Specifying security-specific contact information will help ensure that security advisories sent by AWS reach the team in your organization that is best equipped to respond to them.","RemediationProcedure": "Perform the following to establish security contact information:**From Console:**1. Click on your account name at the top right corner of the console. 2. From the drop-down menu Click `My Account`3. Scroll down to the `Alternate Contacts` section 4. Enter contact information in the `Security` section**Note:** Consider specifying an internal email distribution list to ensure emails are regularly monitored by more than one individual.","AdditionalInformation": ""}],"description": "Ensure security contact information is registered","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.3": {"name": "1.3","checks": {"account_security_questions_are_registered_in_the_aws_account": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "","Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.","DefaultValue": null,"AuditProcedure": "**From Console:**1. Login to the AWS account as the 'root' user 2. On the top right you will see the __ 3. Click on the __ 4. From the drop-down menu Click `My Account`5. In the `Configure Security Challenge Questions` section on the `Personal Information` page, configure three security challenge questions. 6. Click `Save questions` .","ImpactStatement": "","AssessmentStatus": "Manual","RationaleStatement": "When creating a new AWS account, a default super user is automatically created. This account is referred to as the 'root user' or 'root' account. It is recommended that the use of this account be limited and highly controlled. During events in which the 'root' password is no longer accessible or the MFA token associated with 'root' is lost/destroyed it is possible, through authentication using secret questions and associated answers, to recover 'root' user login access.","RemediationProcedure": "**From Console:**1. Login to the AWS Account as the 'root' user 2. Click on the __ from the top right of the console 3. From the drop-down menu Click _My Account_ 4. Scroll down to the `Configure Security Questions` section 5. Click on `Edit`6. Click on each `Question` - From the drop-down select an appropriate question- Click on the `Answer` section- Enter an appropriate answer - Follow process for all 3 questions 7. Click `Update` when complete 8. Save Questions and Answers and place in a secure physical location","AdditionalInformation": ""}],"description": "Ensure security questions are registered in the AWS account","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.4": {"name": "1.4","checks": {"iam_no_root_access_key": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "http://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html:http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html:http://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccountSummary.html:https://aws.amazon.com/blogs/security/an-easier-way-to-determine-the-presence-of-aws-account-access-keys/","Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if the 'root' user account has access keys:**From Console:**1. Login to the AWS Management Console 2. Click `Services`3. Click `IAM`4. Click on `Credential Report`5. This will download a `.csv` file which contains credential usage for all IAM users within an AWS Account - open this file 6. For the `` user, ensure the `access_key_1_active` and `access_key_2_active` fields are set to `FALSE` .**From Command Line:**Run the following command: ```aws iam get-account-summary | grep \"AccountAccessKeysPresent\"``` If no 'root' access keys exist the output will show \"AccountAccessKeysPresent\": 0,. If the output shows a \"1\" than 'root' keys exist, refer to the remediation procedure below.","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Removing access keys associated with the 'root' user account limits vectors by which the account can be compromised. Additionally, removing the 'root' access keys encourages the creation and use of role based accounts that are least privileged.","RemediationProcedure": "Perform the following to delete or disable active 'root' user access keys**From Console:**1. Sign in to the AWS Management Console as 'root' and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). 2. Click on __ at the top right and select `My Security Credentials` from the drop down list 3. On the pop out screen Click on `Continue to Security Credentials`4. Click on `Access Keys` _(Access Key ID and Secret Access Key)_ 5. Under the `Status` column if there are any Keys which are Active- Click on `Make Inactive` - (Temporarily disable Key - may be needed again)- Click `Delete` - (Deleted keys cannot be recovered)","AdditionalInformation": "IAM User account \"root\" for us-gov cloud regions is not enabled by default. However, on request to AWS support enables 'root' access only through access-keys (CLI, API methods) for us-gov cloud region."}],"description": "Ensure no 'root' user account access key exists","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.5": {"name": "1.5","checks": {"iam_root_mfa_enabled": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html#enable-virt-mfa-for-root","Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.**Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if the 'root' user account has MFA setup:**From Console:**1. Login to the AWS Management Console 2. Click `Services`3. Click `IAM`4. Click on `Credential Report`5. This will download a `.csv` file which contains credential usage for all IAM users within an AWS Account - open this file 6. For the `` user, ensure the `mfa_active` field is set to `TRUE` .**From Command Line:**1. Run the following command: ```aws iam get-account-summary | grep \"AccountMFAEnabled\" ``` 2. Ensure the AccountMFAEnabled property is set to 1","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Enabling MFA provides increased security for console access as it requires the authenticating principal to possess a device that emits a time-sensitive key and have knowledge of a credential.","RemediationProcedure": "Perform the following to establish MFA for the 'root' user account:1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). Note: to manage MFA devices for the 'root' AWS account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials.2. Choose `Dashboard` , and under `Security Status` , expand `Activate MFA` on your root account. 3. Choose `Activate MFA`4. In the wizard, choose `A virtual MFA` device and then choose `Next Step` . 5. IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the 'secret configuration key' that is available for manual entry on devices that do not support QR codes. 6. Open your virtual MFA application. (For a list of apps that you can use for hosting virtual MFA devices, see [Virtual MFA Applications](http://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications).) If the virtual MFA application supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device). 7. Determine whether the MFA app supports QR codes, and then do one of the following: - Use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to Scan code, and then use the device's camera to scan the code.- In the Manage MFA Device wizard, choose Show secret key for manual configuration, and then type the secret configuration key into your MFA application.When you are finished, the virtual MFA device starts generating one-time passwords.In the Manage MFA Device wizard, in the Authentication Code 1 box, type the one-time password that currently appears in the virtual MFA device. Wait up to 30 seconds for the device to generate a new one-time password. Then type the second one-time password into the Authentication Code 2 box. Choose Assign Virtual MFA.","AdditionalInformation": "IAM User account \"root\" for us-gov cloud regions does not have console access. This recommendation is not applicable for us-gov cloud regions."}],"description": "Ensure MFA is enabled for the 'root' user account","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.6": {"name": "1.6","checks": {"iam_root_hardware_mfa_enabled": null},"status": "PASS","attributes": [{"Profile": "Level 2","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_physical.html#enable-hw-mfa-for-root","Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if the 'root' user account has a hardware MFA setup:1. Run the following command to determine if the 'root' account has MFA setup: ```aws iam get-account-summary | grep \"AccountMFAEnabled\" ```The `AccountMFAEnabled` property is set to `1` will ensure that the 'root' user account has MFA (Virtual or Hardware) Enabled. If `AccountMFAEnabled` property is set to `0` the account is not compliant with this recommendation.2. If `AccountMFAEnabled` property is set to `1`, determine 'root' account has Hardware MFA enabled. Run the following command to list all virtual MFA devices: ```aws iam list-virtual-mfa-devices``` If the output contains one MFA with the following Serial Number, it means the MFA is virtual, not hardware and the account is not compliant with this recommendation: `\"SerialNumber\": \"arn:aws:iam::__:mfa/root-account-mfa-device\"`","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "A hardware MFA has a smaller attack surface than a virtual MFA. For example, a hardware MFA does not suffer the attack surface introduced by the mobile smartphone on which a virtual MFA resides.**Note**: Using hardware MFA for many, many AWS accounts may create a logistical device management issue. If this is the case, consider implementing this Level 2 recommendation selectively to the highest security AWS accounts and the Level 1 recommendation applied to the remaining accounts.","RemediationProcedure": "Perform the following to establish a hardware MFA for the 'root' user account:1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/). Note: to manage MFA devices for the AWS 'root' user account, you must use your 'root' account credentials to sign in to AWS. You cannot manage MFA devices for the 'root' account using other credentials. 2. Choose `Dashboard` , and under `Security Status` , expand `Activate MFA` on your root account. 3. Choose `Activate MFA`4. In the wizard, choose `A hardware MFA` device and then choose `Next Step` . 5. In the `Serial Number` box, enter the serial number that is found on the back of the MFA device. 6. In the `Authentication Code 1` box, enter the six-digit number displayed by the MFA device. You might need to press the button on the front of the device to display the number. 7. Wait 30 seconds while the device refreshes the code, and then enter the next six-digit number into the `Authentication Code 2` box. You might need to press the button on the front of the device again to display the second number. 8. Choose `Next Step` . The MFA device is now associated with the AWS account. The next time you use your AWS account credentials to sign in, you must type a code from the hardware MFA device.Remediation for this recommendation is not available through AWS CLI.","AdditionalInformation": "IAM User account 'root' for us-gov cloud regions does not have console access. This control is not applicable for us-gov cloud regions."}],"description": "Ensure hardware MFA is enabled for the 'root' user account","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.7": {"name": "1.7","checks": {"iam_avoid_root_usage": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html:https://docs.aws.amazon.com/general/latest/gr/aws_tasks-that-require-root.html","Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.","DefaultValue": null,"AuditProcedure": "**From Console:**1. Login to the AWS Management Console at `https://console.aws.amazon.com/iam/` 2. In the left pane, click `Credential Report` 3. Click on `Download Report` 4. Open of Save the file locally 5. Locate the `` under the user column 6. Review `password_last_used, access_key_1_last_used_date, access_key_2_last_used_date` to determine when the 'root user' was last used.**From Command Line:**Run the following CLI commands to provide a credential report for determining the last time the 'root user' was used: ``` aws iam generate-credential-report ``` ``` aws iam get-credential-report --query 'Content' --output text | base64 -d | cut -d, -f1,5,11,16 | grep -B1 '' ```Review `password_last_used`, `access_key_1_last_used_date`, `access_key_2_last_used_date` to determine when the _root user_ was last used.**Note:** There are a few conditions under which the use of the 'root' user account is required. Please see the reference links for all of the tasks that require use of the 'root' user.","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "The 'root user' has unrestricted access to and control over all account resources. Use of it is inconsistent with the principles of least privilege and separation of duties, and can lead to unnecessary harm due to error or account compromise.","RemediationProcedure": "If you find that the 'root' user account is being used for daily activity to include administrative tasks that do not require the 'root' user:1. Change the 'root' user password. 2. Deactivate or delete any access keys associate with the 'root' user.**Remember, anyone who has 'root' user credentials for your AWS account has unrestricted access to and control of all the resources in your account, including billing information.","AdditionalInformation": "The 'root' user for us-gov cloud regions is not enabled by default. However, on request to AWS support, they can enable the 'root' user and grant access only through access-keys (CLI, API methods) for us-gov cloud region. If the 'root' user for us-gov cloud regions is enabled, this recommendation is applicable.Monitoring usage of the 'root' user can be accomplished by implementing recommendation 3.3 Ensure a log metric filter and alarm exist for usage of the 'root' user."}],"description": "Eliminate use of the 'root' user for administrative and daily tasks","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.8": {"name": "1.8","checks": {"iam_password_policy_minimum_length_14": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy","Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure the password policy is configured as prescribed:**From Console:**1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Ensure \"Minimum password length\" is set to 14 or greater.**From Command Line:** ``` aws iam get-account-password-policy ``` Ensure the output of the above command includes \"MinimumPasswordLength\": 14 (or higher)","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Setting a password complexity policy increases account resiliency against brute force login attempts.","RemediationProcedure": "Perform the following to set the password policy as prescribed:**From Console:**1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Set \"Minimum password length\" to `14` or greater. 5. Click \"Apply password policy\"**From Command Line:** ```aws iam update-account-password-policy --minimum-password-length 14 ``` Note: All commands starting with \"aws iam update-account-password-policy\" can be combined into a single command.","AdditionalInformation": ""}],"description": "Ensure IAM password policy requires minimum length of 14 or greater","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"1.9": {"name": "1.9","checks": {"iam_password_policy_reuse_24": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "1. Identity and Access Management","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html:https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#configure-strong-password-policy","Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure the password policy is configured as prescribed:**From Console:**1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Ensure \"Prevent password reuse\" is checked 5. Ensure \"Number of passwords to remember\" is set to 24**From Command Line:** ``` aws iam get-account-password-policy``` Ensure the output of the above command includes \"PasswordReusePrevention\": 24","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Preventing password reuse increases account resiliency against brute force login attempts.","RemediationProcedure": "Perform the following to set the password policy as prescribed:**From Console:**1. Login to AWS Console (with appropriate permissions to View Identity Access Management Account Settings) 2. Go to IAM Service on the AWS Console 3. Click on Account Settings on the Left Pane 4. Check \"Prevent password reuse\" 5. Set \"Number of passwords to remember\" is set to `24` **From Command Line:** ```aws iam update-account-password-policy --password-reuse-prevention 24 ``` Note: All commands starting with \"aws iam update-account-password-policy\" can be combined into a single command.","AdditionalInformation": ""}],"description": "Ensure IAM password policy prevents password reuse","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"3.1": {"name": "3.1","checks": {"cloudtrail_multi_region_enabled": "PASS"},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "3. Logging","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-concepts.html#cloudtrail-concepts-management-events:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-and-data-events-with-cloudtrail.html?icmpid=docs_cloudtrail_console#logging-management-events:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-supported-services.html#cloud-trail-supported-services-data-events","Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).","DefaultValue": null,"AuditProcedure": "Perform the following to determine if CloudTrail is enabled for all regions:**From Console:**1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. Click on `Trails` on the left navigation pane- You will be presented with a list of trails across all regions 3. Ensure at least one Trail has `All` specified in the `Region` column 4. Click on a trail via the link in the _Name_ column 5. Ensure `Logging` is set to `ON`6. Ensure `Apply trail to all regions` is set to `Yes` 7. In section `Management Events` ensure `Read/Write Events` set to `ALL`**From Command Line:** ```aws cloudtrail describe-trails ``` Ensure `IsMultiRegionTrail` is set to `true```` aws cloudtrail get-trail-status --name ``` Ensure `IsLogging` is set to `true` ``` aws cloudtrail get-event-selectors --trail-name ``` Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`","ImpactStatement": "S3 lifecycle features can be used to manage the accumulation and management of logs over time. See the following AWS resource for more information on these features:1. https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html","AssessmentStatus": "Automated","RationaleStatement": "The AWS API call history produced by CloudTrail enables security analysis, resource change tracking, and compliance auditing. Additionally, - ensuring that a multi-regions trail exists will ensure that unexpected activity occurring in otherwise unused regions is detected- ensuring that a multi-regions trail exists will ensure that `Global Service Logging` is enabled for a trail by default to capture recording of events generated onAWS global services- for a multi-regions trail, ensuring that management events configured for all type of Read/Writes ensures recording of management operations that are performed on all resources in an AWS account","RemediationProcedure": "Perform the following to enable global (Multi-region) CloudTrail logging:**From Console:**1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. Click on _Trails_ on the left navigation pane 3. Click `Get Started Now` , if presented- Click `Add new trail` - Enter a trail name in the `Trail name` box- Set the `Apply trail to all regions` option to `Yes` - Specify an S3 bucket name in the `S3 bucket` box- Click `Create`4. If 1 or more trails already exist, select the target trail to enable for global logging 5. Click the edit icon (pencil) next to `Apply trail to all regions` , Click `Yes` and Click `Save`. 6. Click the edit icon (pencil) next to `Management Events` click `All` for setting `Read/Write Events` and Click `Save`.**From Command Line:** ``` aws cloudtrail create-trail --name --bucket-name --is-multi-region-trailaws cloudtrail update-trail --name --is-multi-region-trail ```Note: Creating CloudTrail via CLI without providing any overriding options configures `Management Events` to set `All` type of `Read/Writes` by default.","AdditionalInformation": ""}],"description": "Ensure CloudTrail is enabled in all regions","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"3.2": {"name": "3.2","checks": {"cloudtrail_log_file_validation_enabled": "FAIL"},"status": "FAIL","attributes": [{"Profile": "Level 2","Section": "3. Logging","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-enabling.html","Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.","DefaultValue": null,"AuditProcedure": "Perform the following on each trail to determine if log file validation is enabled:**From Console:**1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. Click on `Trails` on the left navigation pane 3. For Every Trail: - Click on a trail via the link in the _Name_ column - Under the `General details` section, ensure `Log file validation` is set to `Enabled` **From Command Line:** ``` aws cloudtrail describe-trails ``` Ensure `LogFileValidationEnabled` is set to `true` for each trail","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Enabling log file validation will provide additional integrity checking of CloudTrail logs.","RemediationProcedure": "Perform the following to enable log file validation on a given trail:**From Console:**1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. Click on `Trails` on the left navigation pane 3. Click on target trail 4. Within the `General details` section click `edit` 5. Under the `Advanced settings` section 6. Check the enable box under `Log file validation`7. Click `Save changes` **From Command Line:** ``` aws cloudtrail update-trail --name --enable-log-file-validation ``` Note that periodic validation of logs using these digests can be performed by running the following command: ``` aws cloudtrail validate-logs --trail-arn --start-time --end-time ```","AdditionalInformation": ""}],"description": "Ensure CloudTrail log file validation is enabled","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3.3": {"name": "3.3","checks": {"cloudtrail_logs_s3_bucket_is_not_publicly_accessible": "PASS"},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "3. Logging","References": "https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html","Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if any public access is granted to an S3 bucket via an ACL or S3 bucket policy:**From Console:**1. Go to the Amazon CloudTrail console at [https://console.aws.amazon.com/cloudtrail/home](https://console.aws.amazon.com/cloudtrail/home) 2. In the `API activity history` pane on the left, click `Trails`3. In the `Trails` pane, note the bucket names in the `S3 bucket` column 4. Go to Amazon S3 console at [https://console.aws.amazon.com/s3/home](https://console.aws.amazon.com/s3/home) 5. For each bucket noted in step 3, right-click on the bucket and click `Properties`6. In the `Properties` pane, click the `Permissions` tab. 7. The tab shows a list of grants, one row per grant, in the bucket ACL. Each row identifies the grantee and the permissions granted. 8. Ensure no rows exists that have the `Grantee` set to `Everyone` or the `Grantee` set to `Any Authenticated User.`9. If the `Edit bucket policy` button is present, click it to review the bucket policy. 10. Ensure the policy does not contain a `Statement` having an `Effect` set to `Allow` and a `Principal` set to \"\\*\" or {\"AWS\" : \"\\*\"}**From Command Line:**1. Get the name of the S3 bucket that CloudTrail is logging to: ```aws cloudtrail describe-trails --query 'trailList[*].S3BucketName' ``` 2. Ensure the `AllUsers` principal is not granted privileges to that `` : ```aws s3api get-bucket-acl --bucket --query 'Grants[?Grantee.URI== `https://acs.amazonaws.com/groups/global/AllUsers` ]' ``` 3. Ensure the `AuthenticatedUsers` principal is not granted privileges to that ``: ```aws s3api get-bucket-acl --bucket --query 'Grants[?Grantee.URI== `https://acs.amazonaws.com/groups/global/Authenticated Users` ]' ``` 4. Get the S3 Bucket Policy ```aws s3api get-bucket-policy --bucket ``` 5. Ensure the policy does not contain a `Statement` having an `Effect` set to `Allow` and a `Principal` set to \"\\*\" or {\"AWS\" : \"\\*\"}**Note:** Principal set to \"\\*\" or {\"AWS\" : \"\\*\"} allows anonymous access.","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Allowing public access to CloudTrail log content may aid an adversary in identifying weaknesses in the affected account's use or configuration.","RemediationProcedure": "Perform the following to remove any public access that has been granted to the bucket via an ACL or S3 bucket policy:1. Go to Amazon S3 console at [https://console.aws.amazon.com/s3/home](https://console.aws.amazon.com/s3/home) 2. Right-click on the bucket and click Properties 3. In the `Properties` pane, click the `Permissions` tab. 4. The tab shows a list of grants, one row per grant, in the bucket ACL. Each row identifies the grantee and the permissions granted. 5. Select the row that grants permission to `Everyone` or `Any Authenticated User`6. Uncheck all the permissions granted to `Everyone` or `Any Authenticated User` (click `x` to delete the row). 7. Click `Save` to save the ACL. 8. If the `Edit bucket policy` button is present, click it. 9. Remove any `Statement` having an `Effect` set to `Allow` and a `Principal` set to \"\\*\" or {\"AWS\" : \"\\*\"}.","AdditionalInformation": ""}],"description": "Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible","checks_status": {"fail": 0,"pass": 1,"total": 1,"manual": 0}},"3.4": {"name": "3.4","checks": {"cloudtrail_cloudwatch_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Profile": "Level 1","Section": "3. Logging","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/how-cloudtrail-works.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-aws-service-specific-topics.html","Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs.Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure CloudTrail is configured as prescribed:**From Console:**1. Login to the CloudTrail console at `https://console.aws.amazon.com/cloudtrail/` 2. Under `Trails` , click on the CloudTrail you wish to evaluate 3. Under the `CloudWatch Logs` section. 4. Ensure a `CloudWatch Logs` log group is configured and listed. 5. Under `General details` confirm `Last log file delivered` has a recent (~one day old) timestamp.**From Command Line:**1. Run the following command to get a listing of existing trails: ```aws cloudtrail describe-trails ``` 2. Ensure `CloudWatchLogsLogGroupArn` is not empty and note the value of the `Name` property. 3. Using the noted value of the `Name` property, run the following command: ```aws cloudtrail get-trail-status --name ``` 4. Ensure the `LatestcloudwatchLogdDeliveryTime` property is set to a recent (~one day old) timestamp.If the `CloudWatch Logs` log group is not setup and the delivery time is not recent refer to the remediation below.","ImpactStatement": "Note: By default, CloudWatch Logs will store Logs indefinitely unless a specific retention period is defined for the log group. When choosing the number of days to retain, keep in mind the average days it takes an organization to realize they have been breached is 210 days (at the time of this writing). Since additional time is required to research a breach, a minimum 365 day retention policy allows time for detection and research. You may also wish to archive the logs to a cheaper storage service rather than simply deleting them. See the following AWS resource to manage CloudWatch Logs retention periods:1. https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/SettingLogRetention.html","AssessmentStatus": "Automated","RationaleStatement": "Sending CloudTrail logs to CloudWatch Logs will facilitate real-time and historic activity logging based on user, API, resource, and IP address, and provides opportunity to establish alarms and notifications for anomalous or sensitivity account activity.","RemediationProcedure": "Perform the following to establish the prescribed state:**From Console:**1. Login to the CloudTrail console at `https://console.aws.amazon.com/cloudtrail/` 2. Select the `Trail` the needs to be updated. 3. Scroll down to `CloudWatch Logs` 4. Click `Edit` 5. Under `CloudWatch Logs` click the box `Enabled` 6. Under `Log Group` pick new or select an existing log group 7. Edit the `Log group name` to match the CloudTrail or pick the existing CloudWatch Group. 8. Under `IAM Role` pick new or select an existing. 9. Edit the `Role name` to match the CloudTrail or pick the existing IAM Role. 10. Click `Save changes.**From Command Line:** ``` aws cloudtrail update-trail --name --cloudwatch-logs-log-group-arn --cloudwatch-logs-role-arn ```","AdditionalInformation": ""}],"description": "Ensure CloudTrail trails are integrated with CloudWatch Logs","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3.5": {"name": "3.5","checks": {"config_recorder_all_regions_enabled": null},"status": "PASS","attributes": [{"Profile": "Level 2","Section": "3. Logging","References": "https://docs.aws.amazon.com/cli/latest/reference/configservice/describe-configuration-recorder-status.html","Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.","DefaultValue": null,"AuditProcedure": "Process to evaluate AWS Config configuration per region**From Console:**1. Sign in to the AWS Management Console and open the AWS Config console at [https://console.aws.amazon.com/config/](https://console.aws.amazon.com/config/). 2. On the top right of the console select target Region. 3. If presented with Setup AWS Config - follow remediation procedure: 4. On the Resource inventory page, Click on edit (the gear icon). The Set Up AWS Config page appears. 5. Ensure 1 or both check-boxes under \"All Resources\" is checked.- Include global resources related to IAM resources - which needs to be enabled in 1 region only 6. Ensure the correct S3 bucket has been defined. 7. Ensure the correct SNS topic has been defined. 8. Repeat steps 2 to 7 for each region.**From Command Line:**1. Run this command to show all AWS Config recorders and their properties: ``` aws configservice describe-configuration-recorders ``` 2. Evaluate the output to ensure that there's at least one recorder for which `recordingGroup` object includes `\"allSupported\": true` AND `\"includeGlobalResourceTypes\": true`Note: There is one more parameter \"ResourceTypes\" in recordingGroup object. We don't need to check the same as whenever we set \"allSupported\": true, AWS enforces resource types to be empty (\"ResourceTypes\":[])Sample Output:``` {\"ConfigurationRecorders\": [{\"recordingGroup\": {\"allSupported\": true,\"resourceTypes\": [],\"includeGlobalResourceTypes\": true},\"roleARN\": \"arn:aws:iam:::role/service-role/\",\"name\": \"default\"}] } ```3. Run this command to show the status for all AWS Config recorders: ``` aws configservice describe-configuration-recorder-status ``` 4. In the output, find recorders with `name` key matching the recorders that met criteria in step 2. Ensure that at least one of them includes `\"recording\": true` and `\"lastStatus\": \"SUCCESS\"`","ImpactStatement": "It is recommended AWS Config be enabled in all regions.","AssessmentStatus": "Automated","RationaleStatement": "The AWS configuration item history captured by AWS Config enables security analysis, resource change tracking, and compliance auditing.","RemediationProcedure": "To implement AWS Config configuration:**From Console:**1. Select the region you want to focus on in the top right of the console 2. Click `Services`3. Click `Config`4. Define which resources you want to record in the selected region 5. Choose to include global resources (IAM resources) 6. Specify an S3 bucket in the same account or in another managed AWS account 7. Create an SNS Topic from the same AWS account or another managed AWS account**From Command Line:**1. Ensure there is an appropriate S3 bucket, SNS topic, and IAM role per the [AWS Config Service prerequisites](http://docs.aws.amazon.com/config/latest/developerguide/gs-cli-prereq.html). 2. Run this command to set up the configuration recorder ``` aws configservice subscribe --s3-bucket my-config-bucket --sns-topic arn:aws:sns:us-east-1:012345678912:my-config-notice --iam-role arn:aws:iam::012345678912:role/myConfigRole ``` 3. Run this command to start the configuration recorder: ``` start-configuration-recorder --configuration-recorder-name ```","AdditionalInformation": ""}],"description": "Ensure AWS Config is enabled in all regions","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"3.6": {"name": "3.6","checks": {"cloudtrail_logs_s3_bucket_access_logging_enabled": "FAIL"},"status": "FAIL","attributes": [{"Profile": "Level 1","Section": "3. Logging","References": "https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html","Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.","DefaultValue": null,"AuditProcedure": "Perform the following ensure the CloudTrail S3 bucket has access logging is enabled:**From Console:**1. Go to the Amazon CloudTrail console at [https://console.aws.amazon.com/cloudtrail/home](https://console.aws.amazon.com/cloudtrail/home) 2. In the API activity history pane on the left, click Trails 3. In the Trails pane, note the bucket names in the S3 bucket column 4. Sign in to the AWS Management Console and open the S3 console at [https://console.aws.amazon.com/s3](https://console.aws.amazon.com/s3). 5. Under `All Buckets` click on a target S3 bucket 6. Click on `Properties` in the top right of the console 7. Under `Bucket:` _ `` _ click on `Logging`8. Ensure `Enabled` is checked.**From Command Line:**1. Get the name of the S3 bucket that CloudTrail is logging to: ```aws cloudtrail describe-trails --query 'trailList[*].S3BucketName'``` 2. Ensure Bucket Logging is enabled: ``` aws s3api get-bucket-logging --bucket ``` Ensure command does not returns empty output.Sample Output for a bucket with logging enabled:``` {\"LoggingEnabled\": {\"TargetPrefix\": \"\",\"TargetBucket\": \"\"} } ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "By enabling S3 bucket logging on target S3 buckets, it is possible to capture all events which may affect objects within any target buckets. Configuring logs to be placed in a separate bucket allows access to log information which can be useful in security and incident response workflows.","RemediationProcedure": "Perform the following to enable S3 bucket logging:**From Console:**1. Sign in to the AWS Management Console and open the S3 console at [https://console.aws.amazon.com/s3](https://console.aws.amazon.com/s3). 2. Under `All Buckets` click on the target S3 bucket 3. Click on `Properties` in the top right of the console 4. Under `Bucket:` click on `Logging`5. Configure bucket logging- Click on the `Enabled` checkbox- Select Target Bucket from list- Enter a Target Prefix 6. Click `Save`.**From Command Line:**1. Get the name of the S3 bucket that CloudTrail is logging to: ``` aws cloudtrail describe-trails --region --query trailList[*].S3BucketName ``` 2. Copy and add target bucket name at ``, Prefix for logfile at `` and optionally add an email address in the following template and save it as ``: ``` {\"LoggingEnabled\": {\"TargetBucket\": \"\",\"TargetPrefix\": \"\",\"TargetGrants\": [{\"Grantee\": {\"Type\": \"AmazonCustomerByEmail\",\"EmailAddress\": \"\"},\"Permission\": \"FULL_CONTROL\"}]}} ``` 3. Run the `put-bucket-logging` command with bucket name and `` as input, for more information refer at [put-bucket-logging](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-logging.html): ``` aws s3api put-bucket-logging --bucket --bucket-logging-status file:// ```","AdditionalInformation": ""}],"description": "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3.7": {"name": "3.7","checks": {"cloudtrail_kms_encryption_enabled": "FAIL"},"status": "FAIL","attributes": [{"Profile": "Level 2","Section": "3. Logging","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html:https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html","Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if CloudTrail is configured to use SSE-KMS:**From Console:**1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. In the left navigation pane, choose `Trails` . 3. Select a Trail 4. Under the `S3` section, ensure `Encrypt log files` is set to `Yes` and a KMS key ID is specified in the `KSM Key Id` field.**From Command Line:**1. Run the following command: ```aws cloudtrail describe-trails``` 2. For each trail listed, SSE-KMS is enabled if the trail has a `KmsKeyId` property defined.","ImpactStatement": "Customer created keys incur an additional cost. See https://aws.amazon.com/kms/pricing/ for more information.","AssessmentStatus": "Automated","RationaleStatement": "Configuring CloudTrail to use SSE-KMS provides additional confidentiality controls on log data as a given user must have S3 read permission on the corresponding log bucket and must be granted decrypt permission by the CMK policy.","RemediationProcedure": "Perform the following to configure CloudTrail to use SSE-KMS:**From Console:**1. Sign in to the AWS Management Console and open the CloudTrail console at [https://console.aws.amazon.com/cloudtrail](https://console.aws.amazon.com/cloudtrail) 2. In the left navigation pane, choose `Trails` . 3. Click on a Trail 4. Under the `S3` section click on the edit button (pencil icon) 5. Click `Advanced`6. Select an existing CMK from the `KMS key Id` drop-down menu- Note: Ensure the CMK is located in the same region as the S3 bucket- Note: You will need to apply a KMS Key policy on the selected CMK in order for CloudTrail as a service to encrypt and decrypt log files using the CMK provided. Steps are provided [here](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-kms-key-policy-for-cloudtrail.html) for editing the selected CMK Key policy 7. Click `Save`8. You will see a notification message stating that you need to have decrypt permissions on the specified KMS key to decrypt log files. 9. Click `Yes` **From Command Line:** ``` aws cloudtrail update-trail --name --kms-id aws kms put-key-policy --key-id --policy ```","AdditionalInformation": "3 statements which need to be added to the CMK policy:1\\. Enable Cloudtrail to describe CMK properties ``` {\"Sid\": \"Allow CloudTrail access\",\"Effect\": \"Allow\",\"Principal\": {\"Service\": \"cloudtrail.amazonaws.com\"},\"Action\": \"kms:DescribeKey\",\"Resource\": \"*\" } ``` 2\\. Granting encrypt permissions ``` {\"Sid\": \"Allow CloudTrail to encrypt logs\",\"Effect\": \"Allow\",\"Principal\": {\"Service\": \"cloudtrail.amazonaws.com\"},\"Action\": \"kms:GenerateDataKey*\",\"Resource\": \"*\",\"Condition\": {\"StringLike\": {\"kms:EncryptionContext:aws:cloudtrail:arn\": [\"arn:aws:cloudtrail:*:aws-account-id:trail/*\"]}} } ``` 3\\. Granting decrypt permissions ``` {\"Sid\": \"Enable CloudTrail log decrypt permissions\",\"Effect\": \"Allow\",\"Principal\": {\"AWS\": \"arn:aws:iam::aws-account-id:user/username\"},\"Action\": \"kms:Decrypt\",\"Resource\": \"*\",\"Condition\": {\"Null\": {\"kms:EncryptionContext:aws:cloudtrail:arn\": \"false\"}} } ```"}],"description": "Ensure CloudTrail logs are encrypted at rest using KMS CMKs","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"3.8": {"name": "3.8","checks": {"kms_cmk_rotation_enabled": null},"status": "PASS","attributes": [{"Profile": "Level 2","Section": "3. Logging","References": "https://aws.amazon.com/kms/pricing/:https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final","Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.","DefaultValue": null,"AuditProcedure": "**From Console:**1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam](https://console.aws.amazon.com/iam). 2. In the left navigation pane, choose `Customer managed keys` 3. Select a customer managed CMK where `Key spec = SYMMETRIC_DEFAULT` 4. Underneath the `General configuration` panel open the tab `Key rotation` 5. Ensure that the checkbox `Automatically rotate this KMS key every year.` is activated 6. Repeat steps 3 - 5 for all customer managed CMKs where \"Key spec = SYMMETRIC_DEFAULT\"**From Command Line:**1. Run the following command to get a list of all keys and their associated `KeyIds````aws kms list-keys ``` 2. For each key, note the KeyId and run the following command ``` describe-key --key-id ``` 3. If the response contains \"KeySpec = SYMMETRIC_DEFAULT\" run the following command ```aws kms get-key-rotation-status --key-id ``` 4. Ensure `KeyRotationEnabled` is set to `true` 5. Repeat steps 2 - 4 for all remaining CMKs","ImpactStatement": "Creation, management, and storage of CMKs may require additional time from and administrator.","AssessmentStatus": "Automated","RationaleStatement": "Rotating encryption keys helps reduce the potential impact of a compromised key as data encrypted with a new key cannot be accessed with a previous key that may have been exposed. Keys should be rotated every year, or upon event that would result in the compromise of that key.","RemediationProcedure": "**From Console:**1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam](https://console.aws.amazon.com/iam). 2. In the left navigation pane, choose `Customer managed keys` . 3. Select a customer managed CMK where `Key spec = SYMMETRIC_DEFAULT` 4. Underneath the \"General configuration\" panel open the tab \"Key rotation\" 5. Check the \"Automatically rotate this KMS key every year.\" checkbox**From Command Line:**1. Run the following command to enable key rotation: ```aws kms enable-key-rotation --key-id ```","AdditionalInformation": ""}],"description": "Ensure rotation for customer created symmetric CMKs is enabled","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"3.9": {"name": "3.9","checks": {"vpc_flow_logs_enabled": "FAIL"},"status": "FAIL","attributes": [{"Profile": "Level 2","Section": "3. Logging","References": "https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/flow-logs.html","Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.","DefaultValue": null,"AuditProcedure": "Perform the following to determine if VPC Flow logs are enabled:**From Console:**1. Sign into the management console 2. Select `Services` then `VPC`3. In the left navigation pane, select `Your VPCs`4. Select a VPC 5. In the right pane, select the `Flow Logs` tab. 6. Ensure a Log Flow exists that has `Active` in the `Status` column.**From Command Line:**1. Run `describe-vpcs` command (OSX/Linux/UNIX) to list the VPC networks available in the current AWS region: ``` aws ec2 describe-vpcs --region --query Vpcs[].VpcId ``` 2. The command output returns the `VpcId` available in the selected region. 3. Run `describe-flow-logs` command (OSX/Linux/UNIX) using the VPC ID to determine if the selected virtual network has the Flow Logs feature enabled: ``` aws ec2 describe-flow-logs --filter \"Name=resource-id,Values=\" ``` 4. If there are no Flow Logs created for the selected VPC, the command output will return an `empty list []`. 5. Repeat step 3 for other VPCs available in the same region. 6. Change the region by updating `--region` and repeat steps 1 - 5 for all the VPCs.","ImpactStatement": "By default, CloudWatch Logs will store Logs indefinitely unless a specific retention period is defined for the log group. When choosing the number of days to retain, keep in mind the average days it takes an organization to realize they have been breached is 210 days (at the time of this writing). Since additional time is required to research a breach, a minimum 365 day retention policy allows time for detection and research. You may also wish to archive the logs to a cheaper storage service rather than simply deleting them. See the following AWS resource to manage CloudWatch Logs retention periods:1. https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/SettingLogRetention.html","AssessmentStatus": "Automated","RationaleStatement": "VPC Flow Logs provide visibility into network traffic that traverses the VPC and can be used to detect anomalous traffic or insight during security workflows.","RemediationProcedure": "Perform the following to determine if VPC Flow logs is enabled:**From Console:**1. Sign into the management console 2. Select `Services` then `VPC`3. In the left navigation pane, select `Your VPCs`4. Select a VPC 5. In the right pane, select the `Flow Logs` tab. 6. If no Flow Log exists, click `Create Flow Log`7. For Filter, select `Reject` 8. Enter in a `Role` and `Destination Log Group`9. Click `Create Log Flow`10. Click on `CloudWatch Logs Group` **Note:** Setting the filter to \"Reject\" will dramatically reduce the logging data accumulation for this recommendation and provide sufficient information for the purposes of breach detection, research and remediation. However, during periods of least privilege security group engineering, setting this the filter to \"All\" can be very helpful in discovering existing traffic flows required for proper operation of an already running environment.**From Command Line:**1. Create a policy document and name it as `role_policy_document.json` and paste the following content: ``` {\"Version\": \"2012-10-17\",\"Statement\": [{\"Sid\": \"test\",\"Effect\": \"Allow\",\"Principal\": {\"Service\": \"ec2.amazonaws.com\"},\"Action\": \"sts:AssumeRole\"}] } ``` 2. Create another policy document and name it as `iam_policy.json` and paste the following content: ``` {\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Action\":[\"logs:CreateLogGroup\",\"logs:CreateLogStream\",\"logs:DescribeLogGroups\",\"logs:DescribeLogStreams\",\"logs:PutLogEvents\",\"logs:GetLogEvents\",\"logs:FilterLogEvents\"],\"Resource\": \"*\"}] } ``` 3. Run the below command to create an IAM role: ``` aws iam create-role --role-name --assume-role-policy-document file://role_policy_document.json``` 4. Run the below command to create an IAM policy: ``` aws iam create-policy --policy-name --policy-document file://iam-policy.json ``` 5. Run `attach-group-policy` command using the IAM policy ARN returned at the previous step to attach the policy to the IAM role (if the command succeeds, no output is returned): ``` aws iam attach-group-policy --policy-arn arn:aws:iam:::policy/ --group-name ``` 6. Run `describe-vpcs` to get the VpcId available in the selected region: ``` aws ec2 describe-vpcs --region ``` 7. The command output should return the VPC Id available in the selected region. 8. Run `create-flow-logs` to create a flow log for the vpc: ``` aws ec2 create-flow-logs --resource-type VPC --resource-ids --traffic-type REJECT --log-group-name --deliver-logs-permission-arn ``` 9. Repeat step 8 for other vpcs available in the selected region. 10. Change the region by updating --region and repeat remediation procedure for other vpcs.","AdditionalInformation": ""}],"description": "Ensure VPC flow logging is enabled in all VPCs","checks_status": {"fail": 1,"pass": 0,"total": 1,"manual": 0}},"4.1": {"name": "4.1","checks": {"cloudwatch_log_metric_filter_unauthorized_api_calls": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "4. Monitoring","References": "https://aws.amazon.com/sns/:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails: `aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with \"Name\":` note ``- From value associated with \"CloudWatchLogsLogGroupArn\" note Example: for CloudWatchLogsLogGroupArn that looks like arn:aws:logs:::log-group:NewGroup:*, would be NewGroup- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name <\"Name\" as shown in describe-trails>`Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this `` that you captured in step 1:``` aws logs describe-metric-filters --log-group-name \"\" ```3. Ensure the output from the above command contains the following:``` \"filterPattern\": \"{ ($.errorCode = *UnauthorizedOperation) || ($.errorCode = AccessDenied*) || ($.sourceIPAddress!=delivery.logs.amazonaws.com) || ($.eventName!=HeadBucket) }\", ```4. Note the \"filterName\" `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4.``` aws cloudwatch describe-alarms --query \"MetricAlarms[?MetricName == `unauthorized_api_calls_metric`]\" ```6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN.``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "This alert may be triggered by normal read-only console activities that attempt to opportunistically gather optional information, but gracefully fail if they don't have permissions.If an excessive number of alerts are being generated then an organization may wish to consider adding read access to the limited IAM user permissions simply to quiet the alerts.In some cases doing this may allow the users to actually view some areas of the system - any additional access given should be reviewed for alignment with the original limited IAM user intent.","AssessmentStatus": "Automated","RationaleStatement": "Monitoring unauthorized API calls will help reveal application errors and may reduce time to detect malicious activity.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for unauthorized API calls and the `` taken from audit step 1. ``` aws logs put-metric-filter --log-group-name \"cloudtrail_log_group_name\" --filter-name \"\" --metric-transformations metricName=unauthorized_api_calls_metric,metricNamespace=CISBenchmark,metricValue=1 --filter-pattern \"{ ($.errorCode = \"*UnauthorizedOperation\") || ($.errorCode = \"AccessDenied*\") || ($.sourceIPAddress!=\"delivery.logs.amazonaws.com\") || ($.eventName!=\"HeadBucket\") }\" ```**Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ``` **Note**: you can execute this command once and then re-use the same topic for all monitoring alarms. **Note**: Capture the TopicArn displayed when creating the SNS Topic in Step 2.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ```**Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name \"unauthorized_api_calls_alarm\" --metric-name \"unauthorized_api_calls_metric\" --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace \"CISBenchmark\" --alarm-actions ```","AdditionalInformation": "Configuring log metric filter and alarm on Multi-region (global) CloudTrail - ensures that activities from all regions (used as well as unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored"}],"description": "Ensure a log metric filter and alarm exist for unauthorized API calls","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.2": {"name": "4.2","checks": {"cloudwatch_log_metric_filter_sign_in_without_mfa": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/viewing_metrics_with_cloudwatch.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all `CloudTrails`:``` aws cloudtrail describe-trails ```- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region `CloudTrail` is active``` aws cloudtrail get-trail-status --name ```Ensure in the output that `IsLogging` is set to `TRUE`- Ensure identified Multi-region 'Cloudtrail' captures all Management Events``` aws cloudtrail get-event-selectors --trail-name ```Ensure in the output there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``: ``` aws logs describe-metric-filters --log-group-name \"\" ``` 3. Ensure the output from the above command contains the following: ``` \"filterPattern\": \"{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") }\" ```Or (To reduce false positives incase Single Sign-On (SSO) is used in organization):``` \"filterPattern\": \"{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") && ($.userIdentity.type = \"IAMUser\") && ($.responseElements.ConsoleLogin = \"Success\") }\" ```4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4.``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ``` 6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic ``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN. ``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Monitoring for single-factor console logins will increase visibility into accounts that are not protected by MFA.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for AWS Management Console sign-in without MFA and the `` taken from audit step 1.Use Command: ``` aws logs put-metric-filter --log-group-name --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") }' ```Or (To reduce false positives incase Single Sign-On (SSO) is used in organization):``` aws logs put-metric-filter --log-group-name --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") && ($.userIdentity.type = \"IAMUser\") && ($.responseElements.ConsoleLogin = \"Success\") }' ```**Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ```**Note**: you can execute this command once and then re-use the same topic for all monitoring alarms.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ```**Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ```","AdditionalInformation": "Configuring log metric filter and alarm on Multi-region (global) CloudTrail - ensures that activities from all regions (used as well as unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored -Filter pattern set to `{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") && ($.userIdentity.type = \"IAMUser\") && ($.responseElements.ConsoleLogin = \"Success\"}` reduces false alarms raised when user logs in via SSO account."}],"description": "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.3": {"name": "4.3","checks": {"cloudwatch_log_metric_filter_root_usage": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails:`aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name `Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``:``` aws logs describe-metric-filters --log-group-name \"\" ```3. Ensure the output from the above command contains the following:``` \"filterPattern\": \"{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != \"AwsServiceEvent\" }\" ```4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4.``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ```6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN.``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Monitoring for 'root' account logins will provide visibility into the use of a fully privileged account and an opportunity to reduce the use of it.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for 'Root' account usage and the `` taken from audit step 1. ``` aws logs put-metric-filter --log-group-name `` --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != \"AwsServiceEvent\" }' ```**Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ```**Note**: you can execute this command once and then re-use the same topic for all monitoring alarms.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ```**Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ```","AdditionalInformation": "**Configuring log metric filter and alarm on Multi-region (global) CloudTrail**- ensures that activities from all regions (used as well as unused) are monitored- ensures that activities on all supported global services are monitored- ensures that all management events across all regions are monitored"}],"description": "Ensure a log metric filter and alarm exist for usage of 'root' account","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.4": {"name": "4.4","checks": {"cloudwatch_log_metric_filter_policy_changes": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails:`aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name `Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``:``` aws logs describe-metric-filters --log-group-name \"\" ```3. Ensure the output from the above command contains the following:``` \"filterPattern\": \"{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}\" ```4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4.``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ```6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN.``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Monitoring changes to IAM policies will help ensure authentication and authorization controls remain intact.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for IAM policy changes and the `` taken from audit step 1. ``` aws logs put-metric-filter --log-group-name `` --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}' ```**Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ```**Note**: you can execute this command once and then re-use the same topic for all monitoring alarms.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ```**Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ```","AdditionalInformation": "Configuring log metric filter and alarm on Multi-region (global) CloudTrail - ensures that activities from all regions (used as well as unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored"}],"description": "Ensure a log metric filter and alarm exist for IAM policy changes","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.5": {"name": "4.5","checks": {"cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled": null},"status": "PASS","attributes": [{"Profile": "Level 1","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails: `aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name `Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``:``` aws logs describe-metric-filters --log-group-name \"\" ```3. Ensure the output from the above command contains the following:``` \"filterPattern\": \"{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }\" ```4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4.``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ```6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN.``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Monitoring changes to CloudTrail's configuration will help ensure sustained visibility to activities performed in the AWS account.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for cloudtrail configuration changes and the `` taken from audit step 1. ``` aws logs put-metric-filter --log-group-name --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' ```**Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ```**Note**: you can execute this command once and then re-use the same topic for all monitoring alarms.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ```**Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ```","AdditionalInformation": "Configuring log metric filter and alarm on Multi-region (global) CloudTrail - ensures that activities from all regions (used as well as unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored"}],"description": "Ensure a log metric filter and alarm exist for CloudTrail configuration changes","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.6": {"name": "4.6","checks": {"cloudwatch_log_metric_filter_authentication_failures": null},"status": "PASS","attributes": [{"Profile": "Level 2","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails: `aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name `Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``: ``` aws logs describe-metric-filters --log-group-name \"\" ``` 3. Ensure the output from the above command contains the following: ``` \"filterPattern\": \"{ ($.eventName = ConsoleLogin) && ($.errorMessage = \"Failed authentication\") }\" ```4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4. ``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ``` 6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic ``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN. ``` Example of valid \"SubscriptionArn\": \"arn:aws:sns::::\" ```","ImpactStatement": "","AssessmentStatus": "Automated","RationaleStatement": "Monitoring failed console logins may decrease lead time to detect an attempt to brute force a credential, which may provide an indicator, such as source IP, that can be used in other event correlation.","RemediationProcedure": "Perform the following to setup the metric filter, alarm, SNS topic, and subscription:1. Create a metric filter based on filter pattern provided which checks for AWS management Console Login Failures and the `` taken from audit step 1. ``` aws logs put-metric-filter --log-group-name --filter-name `` --metric-transformations metricName= `` ,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = \"Failed authentication\") }' ``` **Note**: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.2. Create an SNS topic that the alarm will notify ``` aws sns create-topic --name ``` **Note**: you can execute this command once and then re-use the same topic for all monitoring alarms.3. Create an SNS subscription to the topic created in step 2 ``` aws sns subscribe --topic-arn --protocol --notification-endpoint ``` **Note**: you can execute this command once and then re-use the SNS subscription for all monitoring alarms.4. Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2 ``` aws cloudwatch put-metric-alarm --alarm-name `` --metric-name `` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions ```","AdditionalInformation": "Configuring log metric filter and alarm on Multi-region (global) CloudTrail - ensures that activities from all regions (used as well as unused) are monitored - ensures that activities on all supported global services are monitored - ensures that all management events across all regions are monitored"}],"description": "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures","checks_status": {"fail": 0,"pass": 0,"total": 1,"manual": 0}},"4.7": {"name": "4.7","checks": {"cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk": null},"status": "PASS","attributes": [{"Profile": "Level 2","Section": "4. Monitoring","References": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html:https://docs.aws.amazon.com/sns/latest/dg/SubscribeTopic.html","Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.","DefaultValue": null,"AuditProcedure": "Perform the following to ensure that there is at least one active multi-region CloudTrail with prescribed metric filters and alarms configured:1. Identify the log group name configured for use with active multi-region CloudTrail:- List all CloudTrails: `aws cloudtrail describe-trails`- Identify Multi region Cloudtrails: `Trails with \"IsMultiRegionTrail\" set to true`- From value associated with CloudWatchLogsLogGroupArn note ``Example: for CloudWatchLogsLogGroupArn that looks like `arn:aws:logs:::log-group:NewGroup:*`, `` would be `NewGroup`- Ensure Identified Multi region CloudTrail is active`aws cloudtrail get-trail-status --name `ensure `IsLogging` is set to `TRUE`- Ensure identified Multi-region Cloudtrail captures all Management Events`aws cloudtrail get-event-selectors --trail-name `Ensure there is at least one Event Selector for a Trail with `IncludeManagementEvents` set to `true` and `ReadWriteType` set to `All`2. Get a list of all associated metric filters for this ``: ``` aws logs describe-metric-filters --log-group-name \"\" ``` 3. Ensure the output from the above command contains the following: ``` \"filterPattern\": \"{($.eventSource = kms.amazonaws.com) && (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion)) }\" ``` 4. Note the `` value associated with the `filterPattern` found in step 3.5. Get a list of CloudWatch alarms and filter on the `` captured in step 4. ``` aws cloudwatch describe-alarms --query 'MetricAlarms[?MetricName== ``]' ``` 6. Note the `AlarmActions` value - this will provide the SNS topic ARN value.7. Ensure there is at least one active subscriber to the SNS topic ``` aws sns list-subscriptions-by-topic --topic-arn ``` at least one subscription should have \"SubscriptionArn\" with valid aws ARN. ``` Example of valid \"SubscriptionArn\": \"arn:aws:sns:::