Skip to content

[Chore]: Add comprehensive parameter validation and security checks to main.bicep #53

@PlagueHO

Description

@PlagueHO

Area

Infrastructure (Bicep/infra)

Chore Type

Security improvement

Description

The infra/main.bicep file lacks comprehensive parameter validation that could lead to deployment failures or security issues. Missing validation includes:

  • IP allowlist format validation for aiFoundryIpAllowList parameter
  • Environment name character restrictions and naming conventions
  • Principal ID format validation (should be GUID format)
  • JSON file reference validation for external dependencies
  • Subnet CIDR range validation
  • Resource name validation against Azure naming requirements

Justification

Improves security posture by preventing invalid configurations, reduces deployment failures through early validation, enhances user experience with clear error messages, and ensures compliance with Azure naming and security standards.

Acceptance Criteria

  • Add regex validation for IP addresses and CIDR ranges in aiFoundryIpAllowList
  • Implement environment name character restrictions and length validation
  • Add GUID format validation for principalId parameter
  • Create validation for external JSON file references
  • Add subnet CIDR range format validation
  • Implement Azure resource naming validation patterns
  • Update parameter descriptions with validation requirements
  • Add comprehensive error messages for validation failures
  • Update infrastructure-deployment-bicep-avm.md specification to include parameter validation requirements
  • Test all validation scenarios with valid and invalid inputs

Resolution Documentation

Step 1: Add IP Address and CIDR Validation

@description('Array of public IPv4 addresses or CIDR ranges for Azure AI Foundry allow-list. Format: ["192.168.1.1", "10.0.0.0/24"]')
param aiFoundryIpAllowList array = []

// Add validation function
func isValidIpOrCidr(ipString string) bool => 
  // Regex for IPv4 address
  ipString =~ '^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$' ||
  // Regex for IPv4 CIDR  
  ipString =~ '^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}\\/(3[0-2]|[1-2][0-9]|[0-9])$'

// Validate each IP in the array
var validatedIpList = [for ip in aiFoundryIpAllowList: {
  value: ip
  _validation: isValidIpOrCidr(ip) ? null : error('Invalid IP address or CIDR range: ${ip}')
}]

Step 2: Environment Name Validation

@description('Environment name used for resource naming. Must be 1-40 characters, alphanumeric and hyphens only, cannot start/end with hyphen.')
@minLength(1)
@maxLength(40)
@pattern('^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$')
param environmentName string

Step 3: Principal ID GUID Validation

@description('Azure AD Object ID of the user or service principal. Must be a valid GUID format.')
@pattern('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
param principalId string

Step 4: Azure Resource Name Validation

@description('Storage account name override. Must be 3-24 characters, lowercase letters and numbers only.')
@minLength(3)
@maxLength(24)
@pattern('^[a-z0-9]+$')
param azureStorageAccountName string = 'default'

// Add validation for generated names
var isValidStorageAccountName = length(storageAccountName) >= 3 && length(storageAccountName) <= 24 && 
  storageAccountName =~ '^[a-z0-9]+$'
var storageAccountNameValidation = isValidStorageAccountName ? null : 
  error('Generated storage account name "${storageAccountName}" is invalid. Must be 3-24 characters, lowercase letters and numbers only.')

Step 5: Network Configuration Validation

// Validate subnet CIDR ranges don't overlap and are within address space
func isValidCidr(cidr string) bool => 
  cidr =~ '^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}\\/(3[0-2]|[1-2][0-9]|[0-9])$'

var networkValidation = {
  addressSpaceValid: isValidCidr('10.0.0.0/16')
  subnetsValid: all([
    isValidCidr('10.0.0.0/24'),
    isValidCidr('10.0.1.0/24'),
    isValidCidr('10.0.2.0/24'),
    isValidCidr('10.0.3.0/24'),
    isValidCidr('10.0.255.0/27')
  ])
}

Step 6: JSON File Validation

// Add validation that JSON files exist and are properly formatted
var projectsFromJsonValidation = aiFoundryProjectsFromJson ? 
  (length(loadJsonContent('./sample-ai-foundry-projects.json')) > 0 ? null : 
   error('sample-ai-foundry-projects.json is empty or invalid')) : null

var openAiModelsValidation = deploySampleOpenAiModels ?
  (length(loadJsonContent('./sample-openai-models.json')) > 0 ? null :
   error('sample-openai-models.json is empty or invalid')) : null

Step 7: Add Validation Error Messages

// Add descriptive error messages for common validation failures
var validationErrors = [
  storageAccountNameValidation
  projectsFromJsonValidation 
  openAiModelsValidation
  // Add null checks to filter out successful validations
]
var hasValidationErrors = length(filter(validationErrors, error => error != null)) > 0

Side Effects

  • Breaking Change: Existing deployments with invalid parameter values will fail validation
  • Error Messages: Users will see new validation error messages that may require parameter adjustments
  • Performance: Additional validation logic may slightly increase template processing time
  • Maintenance: Validation patterns may need updates as Azure requirements change

Priority

High - Important for upcoming release

Additional Context

This addresses security and reliability concerns identified in the infrastructure audit. Proper parameter validation is essential for preventing misconfigurations that could lead to security vulnerabilities or deployment failures. Aligns with Azure Well-Architected Framework security pillar recommendations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions