Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Regla KICS: App Service Application Insights Not Configured

## Descripción General

Esta regla verifica que los servicios de Azure App Service y Function Apps tengan configurada la integración con **Application Insights**.

Application Insights es una característica de Azure Monitor que proporciona gestión del rendimiento de aplicaciones (APM) y seguimiento de errores en tiempo real. Para vincular un App Service con Application Insights en Terraform, se debe definir `APPLICATIONINSIGHTS_CONNECTION_STRING` (recomendado) o `APPINSIGHTS_INSTRUMENTATIONKEY` dentro del bloque `app_settings`.

## Lógica de la Regla

La política itera sobre los recursos `azurerm_linux_web_app`, `azurerm_windows_web_app`, `azurerm_linux_function_app` y `azurerm_windows_function_app`.
Verifica la configuración en dos niveles:
1. **Ausencia de app_settings:** Si el bloque no está definido.
2. **Configuración incompleta:** Si el bloque existe pero no contiene las claves de conexión.

## Casos de Fallo Detectados

### Caso 1: Falta Configuración en app_settings

* **Descripción:** El recurso no tiene el bloque `app_settings` definido.
* **Ubicación de la Alerta:** Nivel de recurso principal.

### Caso 2: Claves de App Insights ausentes

* **Descripción:** El bloque `app_settings` existe pero no contiene `APPLICATIONINSIGHTS_CONNECTION_STRING` ni `APPINSIGHTS_INSTRUMENTATIONKEY`.
* **Ubicación de la Alerta:** Atributo `app_settings`.

## Recurso Involucrado

* `azurerm_linux_web_app`
* `azurerm_windows_web_app`
* `azurerm_linux_function_app`
* `azurerm_windows_function_app`

## Solución

Defina `APPLICATIONINSIGHTS_CONNECTION_STRING` dentro de los `app_settings`.

```terraform
resource "azurerm_linux_web_app" "example" {
name = "example-app"
# ...
app_settings = {
"APPLICATIONINSIGHTS_CONNECTION_STRING" = azurerm_application_insights.example.connection_string
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"id": "721c26ff-776f-4d7a-b151-45447712343b",
"queryName": "App Service Application Insights Not Configured",
"severity": "MEDIUM",
"category": "Observability",
"descriptionText": "Ensures that Azure App Services and Function Apps are linked to Application Insights for performance monitoring and error tracking.",
"descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_web_app#app_settings",
"platform": "Terraform",
"descriptionID": "721c26ff",
"cloudProvider": "azure",
"cwe": "CWE-778",
"riskScore": "5.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package Cx

import data.generic.terraform as tf_lib

targets := {
"azurerm_linux_web_app",
"azurerm_windows_web_app",
"azurerm_linux_function_app",
"azurerm_windows_function_app"
}

# REGLA 1: El bloque 'app_settings' no existe en absoluto.
CxPolicy[result] {
doc := input.document[i]
resource_type := targets[t]
app := doc.resource[resource_type][name]

not app.app_settings

result := {
"documentId": doc.id,
"resourceType": resource_type,
"resourceName": tf_lib.get_resource_name(app, name),
"searchKey": sprintf("%s[%s]", [resource_type, name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("'%s.%s' should have 'app_settings' defined", [resource_type, name]),
"keyActualValue": sprintf("'%s.%s' is missing 'app_settings'", [resource_type, name]),
}
}

# REGLA 2: El bloque 'app_settings' existe pero no tiene ninguna clave de App Insights.
CxPolicy[result] {
doc := input.document[i]
resource_type := targets[t]
app := doc.resource[resource_type][name]

app.app_settings
not app.app_settings["APPLICATIONINSIGHTS_CONNECTION_STRING"]
not app.app_settings["APPINSIGHTS_INSTRUMENTATIONKEY"]

result := {
"documentId": doc.id,
"resourceType": resource_type,
"resourceName": tf_lib.get_resource_name(app, name),
"searchKey": sprintf("%s[%s].app_settings", [resource_type, name]),
"issueType": "IncorrectValue",
"keyExpectedValue": "'app_settings' should contain 'APPLICATIONINSIGHTS_CONNECTION_STRING'",
"keyActualValue": "'app_settings' does not contain Application Insights configuration",
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Caso con Connection String (Recomendado)
resource "azurerm_linux_web_app" "pass_connection_string" {
name = "pass-app-1"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

app_settings = {
"APPLICATIONINSIGHTS_CONNECTION_STRING" = "InstrumentationKey=0000;IngestionEndpoint=https://..."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Caso con Instrumentation Key (Legacy)
resource "azurerm_windows_web_app" "pass_instrumentation_key" {
name = "pass-app-2"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

app_settings = {
"APPINSIGHTS_INSTRUMENTATIONKEY" = "0000-0000-0000-0000"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "azurerm_linux_web_app" "fail_no_settings" {
name = "fail-app-no-settings"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
resource "azurerm_windows_web_app" "fail_incomplete_settings" {
name = "fail-app-incomplete"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

app_settings = {
"WEBSITE_NODE_DEFAULT_VERSION" = "14.15.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"queryName": "App Service Application Insights Not Configured",
"severity": "MEDIUM",
"line": 1,
"fileName": "positive1.tf"
},
{
"queryName": "App Service Application Insights Not Configured",
"severity": "MEDIUM",
"line": 7,
"fileName": "positive2.tf"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Regla KICS: App Service HTTP Logs Disabled

## Descripción General

Esta regla verifica que los servicios de Azure App Service (`azurerm_linux_web_app` y `azurerm_windows_web_app`) tengan habilitados los logs HTTP.

Los logs de HTTP registran las solicitudes web que recibe la aplicación, incluyendo la URL solicitada, el agente de usuario, la dirección IP del cliente y el código de estado de la respuesta. Esta información es fundamental para la auditoría de seguridad, el cumplimiento normativo y la resolución de problemas de tráfico.

## Lógica de la Regla

La política itera sobre los recursos de App Service y verifica la configuración en dos pasos:
1. **Ausencia de Logs:** Verifica si el bloque `logs` existe.
2. **Ausencia de Logs HTTP:** Si el bloque `logs` existe, verifica que contenga el sub-bloque `http_logs`.

Si el logging HTTP no está explícitamente habilitado, se genera una alerta.

## Casos de Fallo Detectados

### Caso 1: Configuración de Logs Ausente

* **Descripción:** El recurso App Service se define sin especificar ninguna configuración de `logs`.
* **Ubicación de la Alerta:** Nivel de recurso principal.

### Caso 2: Bloque http_logs Omitido

* **Descripción:** Se define el bloque `logs` (por ejemplo, para logs de aplicación), pero se omiten los logs de tráfico HTTP.
* **Ubicación de la Alerta:** Bloque `logs`.

## Recurso Involucrado

* `azurerm_linux_web_app`
* `azurerm_windows_web_app`

## Solución

Añada el bloque `logs` y configure `http_logs` definiendo un sistema de archivos (`file_system`) o un almacenamiento de blobs (`azure_blob_storage`).

```terraform
resource "azurerm_linux_web_app" "example_secure" {
name = "example-linux-web-app-secure"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
service_plan_id = azurerm_service_plan.example.id

site_config {}

logs {
http_logs {
file_system {
retention_in_days = 7
retention_in_mb = 35
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"id": "72eb3dd8-6892-47d1-9965-a5682de9f4e7",
"queryName": "App Service HTTP Logs Disabled",
"severity": "MEDIUM",
"category": "Observability",
"descriptionText": "Ensures that HTTP logs are enabled for Azure App Services. HTTP logs provide records of HTTP requests to the web app, which are crucial for security monitoring and debugging.",
"descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_web_app#http_logs",
"platform": "Terraform",
"descriptionID": "72eb3dd8",
"cloudProvider": "azure",
"cwe": "CWE-778",
"riskScore": "5.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package Cx

import data.generic.terraform as tf_lib

targets := {"azurerm_linux_web_app", "azurerm_windows_web_app"}

# REGLA 1: El bloque 'logs' no existe en el App Service.
CxPolicy[result] {
doc := input.document[i]
resource_type := targets[t]
app := doc.resource[resource_type][name]

not app.logs

result := {
"documentId": doc.id,
"resourceType": resource_type,
"resourceName": tf_lib.get_resource_name(app, name),
"searchKey": sprintf("%s[%s]", [resource_type, name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("'%s.%s' should have a 'logs' block defined", [resource_type, name]),
"keyActualValue": sprintf("'%s.%s' is missing the 'logs' block", [resource_type, name]),
}
}

# REGLA 2: El bloque 'logs' existe pero no tiene 'http_logs' configurado.
CxPolicy[result] {
doc := input.document[i]
resource_type := targets[t]
app := doc.resource[resource_type][name]

app.logs
not app.logs.http_logs

result := {
"documentId": doc.id,
"resourceType": resource_type,
"resourceName": tf_lib.get_resource_name(app, name),
"searchKey": sprintf("%s[%s].logs", [resource_type, name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("'%s.%s.logs' should have 'http_logs' configured", [resource_type, name]),
"keyActualValue": sprintf("'%s.%s.logs' is missing 'http_logs'", [resource_type, name]),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
resource "azurerm_linux_web_app" "pass_app" {
name = "app-pass"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

logs {
http_logs {
file_system {
retention_in_days = 7
retention_in_mb = 35
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "azurerm_linux_web_app" "fail_no_logs" {
name = "app-fail-1"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

site_config {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
resource "azurerm_windows_web_app" "fail_incomplete_logs" {
name = "app-fail-2"
resource_group_name = "rg"
location = "West Europe"
service_plan_id = "plan-id"

logs {
application_logs {
file_system_level = "Information"
}
# Falta http_logs
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"queryName": "App Service HTTP Logs Disabled",
"severity": "MEDIUM",
"line": 1,
"fileName": "positive1.tf"
},
{
"queryName": "App Service HTTP Logs Disabled",
"severity": "MEDIUM",
"line": 7,
"fileName": "positive2.tf"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Regla KICS: Backup Vault CMK Encryption Disabled

## Descripción General

Esta regla verifica que los almacenes de copias de seguridad de Azure (**Backup Vaults** del servicio Data Protection) estén cifrados utilizando **Customer-Managed Keys (CMK)**.

El uso de claves gestionadas por el cliente proporciona un control total sobre el ciclo de vida de las claves (creación, rotación y revocación) y es un requisito común en entornos con altas exigencias de seguridad y cumplimiento. En Terraform, esto se configura mediante un recurso separado (`azurerm_data_protection_backup_vault_customer_managed_key`) que vincula el Vault con la clave almacenada en un Key Vault.

## Lógica de la Regla

La política realiza un análisis de relaciones entre recursos:
1. Identifica todos los recursos `azurerm_data_protection_backup_vault`.
2. Busca si existe un recurso `azurerm_data_protection_backup_vault_customer_managed_key` cuya propiedad `data_protection_backup_vault_id` apunte al Vault analizado.
3. Verifica que dicho recurso de asociación tenga definido el atributo `key_vault_key_id`.
4. Si no existe esta vinculación, se genera una alerta indicando que el Vault usa claves gestionadas por la plataforma (configuración por defecto).

## Casos de Fallo Detectados

### Caso 1: Backup Vault sin CMK

* **Descripción:** Se define el Backup Vault pero no se encuentra el recurso de asociación de la clave de cifrado gestionada por el cliente.
* **Ubicación de la Alerta:** Sobre el recurso `azurerm_data_protection_backup_vault`.

## Recurso Involucrado

* `azurerm_data_protection_backup_vault`
* `azurerm_data_protection_backup_vault_customer_managed_key`

## Solución

Define el recurso de asociación `azurerm_data_protection_backup_vault_customer_managed_key` y vincúlalo al Vault y a la Key correspondiente.

```terraform
resource "azurerm_data_protection_backup_vault_customer_managed_key" "example" {
data_protection_backup_vault_id = azurerm_data_protection_backup_vault.example.id
key_vault_key_id = azurerm_key_vault_key.example.id
}
Loading
Loading