Skip to main content

Fundamentos de seguridad de Azure Bicep

Escrito por
Headshot of Mark Johnson

Mark Johnson

feature bicep security

13 de diciembre de 2022

0 minutos de lectura

Esta publicación fue escrita por el embajador de Snyk, Mark Johnson (@tazmainiandevil). Obtén acceso interno a Snyk al registrarte para convertirte en embajador de Snyk.

Azure Bicep gana popularidad día a día y rápidamente se está convirtiendo en el reemplazo de las plantillas de Azure Resource Manager (ARM). En esta publicación, voy a repasar algunos fundamentos de seguridad para usar Bicep. Si no conoces Bicep, te recomiendo consultar la documentación de Microsoft Learn para obtener más información.

Mantén los secretos fuera del control de código fuente

Todos sabemos que queremos mantener nuestros secretos fuera del control de código fuente, pero es muy fácil dejar secretos en los archivos por accidente, sobre todo al probar las configuraciones de Bicep de forma local.

Algunas formas de evitar confirmar secretos son:

  • Pasa los parámetros mediante la línea de comandos.

  • Usa un archivo JSON de parámetros excluido del control de código fuente. Por ejemplo, agrégalos a tu archivo .gitignore si usas Git.

Protege las entradas

Pasar parámetros desde el exterior es una cosa, pero ¿cómo puedes asegurarte de que los secretos estén protegidos y no aparezcan en las salidas? Bicep ofrece un decorador @secure para los parámetros de tipo String y Object. Por ejemplo:

@secure()
param adminPassword string

@secure()
param adminCredentials object

Ten cuidado con las salidas

Agregar salidas a tus módulos de Bicep es muy útil, pero hay algunas cosas que debes tener en cuenta. Si configuras una salida que parece un secreto, Bicep te advertirá que estás exponiendo posibles secretos. La siguiente salida para una cadena de conexión a una cuenta de almacenamiento generaría esa advertencia:

output connection string = 'DefaultEndpointsProtocol=https;AccountName=${storageaccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageaccount.id, storageaccount.apiVersion).keys[0].value}'

Sin embargo, si el valor se agrega a una variable antes de asignarlo a la salida, no se mostraría ninguna advertencia y sería fácil no detectarlo.

var connectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageaccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageaccount.id, storageaccount.apiVersion).keys[0].value}'

output connection string = connectionString

Ahora, veamos qué sucede si se implementa un recurso de cuenta de almacenamiento en Azure con la siguiente configuración:

deploy.bicep
param location string = resourceGroup().location
param tags object = {}
param storageName string = 'stsecureteststore'
param sku string = 'Standard_LRS'

module storageModule 'modules/storage.bicep' = {
  name: 'StorageDeploy'
  params: {
    location: location
    storageName: storageName
    tags: tags
    sku: sku
  }
}

modules/storage.bicep

@description('The storage account name')
@minLength(3)
@maxLength(24)
param storageName string
@description('The storage account location')
param location string
@description('The tags for the storage account')
param tags object
@description('The storage account sku') 
@allowed([ 'Standard_LRS', 'Standard_GRS', 'Standard_GZRS', 'Standard_RAGRS', 'Standard_RAGZRS', 'Standard_ZRS', 'Premium_LRS', 'Premium_ZRS' ])
param sku string = 'Standard_LRS'
@description('The access tier for the blob services') 
@allowed([ 'Hot', 'Cool' ]) 
param accessTier string = 'Hot' 
@description('Allow public access to blobs') 
param allowBlobPublicAccess bool = false 

resource storageaccount 'Microsoft.Storage/storageAccounts@2022-05-01' = {
  name: storageName
  location: location
  kind: 'StorageV2'
  tags: tags
  sku: {
    name: sku
  }
  properties: {
    supportsHttpsTrafficOnly: true
    minimumTlsVersion: 'TLS1_2'
    accessTier: accessTier
    allowBlobPublicAccess: allowBlobPublicAccess
  }
}

var connectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageaccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageaccount.id, storageaccount.apiVersion).keys[0].value}'
output connection string = connectionString

Todas las salidas definidas en Bicep se pueden ver en Implementaciones del grupo de recursos en el que se implementaron los recursos:

Página Implementaciones del portal de Azure para el grupo de recursos rg-security-example, que muestra las implementaciones StorageDeploy y main con estado Correcto

Al revisar las salidas de StorageDeploy, vemos que la conexión muestra la clave de la cuenta en texto sin formato:

Página Outputs de StorageDeploy en Azure Portal que muestra la cadena de conexión de una cuenta de almacenamiento.

Esto significa que cualquier persona con acceso para ver los recursos en Azure Portal puede ver estas salidas. Para mantener una buena postura de seguridad, se recomienda no devolver secretos como salidas en Bicep.

Esperamos que Bicep admita en el futuro el uso del decorador @secure para las salidas, de modo que devolver secretos sea seguro.

Secretos de los recursos

Si devolver secretos desde Bicep es un problema, ¿cómo puedes obtener secretos de un módulo a otro? Una opción es acceder a un recurso existente con la palabra clave existing. Por ejemplo:

param storageName string

resource storageaccount 'Microsoft.Storage/storageAccounts@2022-05-01' existing = {
  name: storageName  
}

var connectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageaccount.id, storageaccount.apiVersion).keys[0].value}'

Esta cadena de conexión podría usarse como entrada para otro recurso.

Secretos de Key Vault

Obtener recursos existentes es una forma de conseguir secretos, pero también puedes usar Key Vault para recuperarlos.

Nota: Asegúrate de que la configuración de acceso de Key Vault permita el acceso a través de "Azure Resource Manager para la implementación de plantillas".

Configuración de acceso a recursos de Azure Resource Manager, con la implementación de plantillas seleccionada, mientras que las máquinas virtuales y el cifrado de discos permanecen desmarcados.

Se accede a Key Vaults de la misma forma que en la sección anterior, mediante la palabra clave existing. Sin embargo, debes tener en cuenta que el método getSecret solo se puede usar al asignar un parámetro de módulo con el decorador @secure:

deploy.bicep
param location string = resourceGroup().location
param tags object
param sqlServerName string
param keyVaultName string
param keyVaultResourceGroupName string
param subscriptionId string = subscription().subscriptionId

resource vaultResource 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
  name: keyVaultName 
  scope: resourceGroup(subscriptionId, keyVaultResourceGroupName  )
}

module sqlModule 'modules/sql.bicep' = {
  name: 'SqlDeploy'
  params: {
    location: location
    tags: tags
    sqlServerName: sqlServerName
    administratorLogin: vaultResource.getSecret('sqlUser')
    administratorLoginPassword: vaultResource.getSecret('sqlPassword')
  }  
}

modules/sql.bicep
@description('The resource location')
param location string
@description('The tags for the resources')
param tags object
@description('The name for the SQL Server')
param sqlServerName string
@secure()
@description('The SQL Administrator Login')
param administratorLogin string
@secure()
@description('The SQL Administrator password')
param administratorLoginPassword string

resource sqlServerResource 'Microsoft.Sql/servers@2022-05-01-preview' = {
  name: sqlServerName
  location: location
  tags:tags
  properties: {
    administratorLogin: administratorLogin
    administratorLoginPassword: administratorLoginPassword
  }
}

Análisis de seguridad de Bicep

El análisis de la infraestructura como código (IaC) es cada vez más popular, y es alentador ver que hay interés en encontrar problemas de seguridad lo antes posible. Snyk ofrece una CLI gratuita que puedes usar para analizar IaC de forma local según estándares de seguridad y cumplimiento. Aunque no admite directamente el formato Bicep, sí permite analizar las plantillas ARM en las que se compila Bicep.

Para compilar Bicep en ARM, debes tener instalada la CLI de Bicep. Para comenzar a usar Snyk CLI, crea una cuenta gratuita y luego instala Snyk CLI con npm. Si tienes Node.js instalado localmente, puedes instalarla ejecutando:

npm install snyk@latest -g

Una vez instalada y configurada, puedes ejecutar el comando:

az bicep build -f {file_name}.bicep

Esto generará un archivo JSON con el mismo nombre que el archivo Bicep. Luego, podrás ejecutar el análisis de Snyk con el comando:

snyk iac test {file_name}.json

Reflexiones finales

Todos debemos pensar en la seguridad. Aunque es un objetivo que cambia constantemente, cuanto más aprendemos, más podemos hacer para ayudar a proteger nuestros recursos. Espero que esta publicación haya sido informativa y te haya dado ideas para proteger tus configuraciones de Bicep.

Seguridad de IaC diseñada para desarrolladores

Snyk protege tu infraestructura como código desde el ciclo de vida del desarrollo de software hasta el runtime en la nube con un motor unificado de políticas como código, para que todos los equipos puedan desarrollar, implementar y operar de forma segura.

Leer más

feature insights context
Blog

Los ataques autónomos ya están aquí. La defensa debe estar a su altura.

Los atacantes autónomos están reduciendo el tiempo disponible para defenderse. Descubre cómo el descubrimiento, la corrección, la validación y la prevención continuos pueden ayudar a los equipos de seguridad a seguirles el ritmo.

Blog

Evo ADS Govern Agent Behavior ya está disponible: controla el uso de MCP

Evo ADS Govern Agent Behavior ya está disponible, comenzando con MCP Governance. Descubre, aprueba, monitorea, registra y bloquea el uso de servidores MCP en los principales agentes de programación con IA.

illustration hero ai
Blog

¿Qué es Agentic AppSec?

Descubre cómo Agentic AppSec usa agentes de IA con contexto, límites definidos y verificación independiente para ejecutar el ciclo de seguridad de aplicaciones.