agentsclimarketplace

Infrastructure as code

Skill fabioc-aloha/Alex_Skill_Mall/plugins/cloud-infrastructure/infrastructure-as-code

Domain: DevOps & Cloud EngineeringFrom its SKILL.md

Install
npx -y skills add fabioc-aloha/Alex_Skill_Mall --skill infrastructure-as-code

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

23.4 KB, ~5.8k tokens by cl100k_base, as published. Nobody here has run it

Infrastructure as Code Skill

Domain: DevOps & Cloud Engineering Inheritance: inheritable Version: 1.0.0 Last Updated: 2026-02-01


Overview

Comprehensive patterns for defining, provisioning, and managing cloud infrastructure through declarative code. Covers major IaC tools (Terraform, Bicep, Pulumi, CloudFormation), best practices for modularity, state management, testing, and GitOps workflows.


IaC Fundamentals

Why Infrastructure as Code?

Manual Infrastructure          Infrastructure as Code
┌─────────────────────┐       ┌─────────────────────┐
│  Click in Console   │       │  Write Code         │
│  Document Steps     │       │  Version Control    │
│  Hope It's Repeated │       │  Review & Approve   │
│  Drift Over Time    │       │  Automated Deploy   │
│  Unclear State      │       │  Consistent State   │
└─────────────────────┘       └─────────────────────┘

Key Benefits

BenefitDescription
RepeatabilitySame code = same infrastructure, every time
Version ControlTrack changes, rollback, audit history
CollaborationCode review, PRs, shared ownership
DocumentationCode IS the documentation
TestingValidate before deploy
SpeedProvision environments in minutes

Declarative vs Imperative

ApproachDescriptionTools
DeclarativeDescribe desired end stateTerraform, Bicep, CloudFormation
ImperativeDescribe steps to reach stateScripts, Ansible, Pulumi (optional)

Prefer declarative — let the tool figure out how to reach the desired state.


Tool Comparison

ToolProviderLanguageStateBest For
TerraformHashiCorpHCLRemote/LocalMulti-cloud, mature ecosystem
OpenTofuLinux FoundationHCLRemote/LocalOSS Terraform fork (BSL-free), drop-in replacement
BicepMicrosoftBicep DSLAzure-managedAzure-native, simple syntax
PulumiPulumiTS/Python/Go/C#Managed/SelfDevelopers who prefer real languages
CloudFormationAWSYAML/JSONAWS-managedAWS-only, deep integration
ARM TemplatesMicrosoftJSONAzure-managedLegacy Azure (prefer Bicep)
CDKAWSTS/Python/JavaAWS-managedDevelopers on AWS

Azure Verified Modules (AVM): For Bicep and Terraform, prefer AVM — Microsoft-maintained, tested, WAF-aligned modules. Reduces boilerplate and enforces best practices. Tracked at registry.terraform.io/namespaces/Azure and Bicep public module registry.


Terraform Patterns

Project Structure

infrastructure/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── terraform.tfvars
│   │   └── backend.tf
│   ├── staging/
│   └── prod/
├── modules/
│   ├── networking/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── compute/
│   └── database/
└── shared/
    └── providers.tf

Basic Resource Pattern

# variables.tf
variable "environment" {
  type        = string
  description = "Environment name (dev, staging, prod)"
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "location" {
  type        = string
  default     = "eastus2"
  description = "Azure region for resources"
}

# main.tf
resource "azurerm_resource_group" "main" {
  name     = "rg-${var.project}-${var.environment}"
  location = var.location

  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
    Project     = var.project
  }
}

# outputs.tf
output "resource_group_id" {
  value       = azurerm_resource_group.main.id
  description = "The ID of the resource group"
}

Module Pattern

# modules/app-service/variables.tf
variable "name" {
  type        = string
  description = "Name of the App Service"
}

variable "resource_group_name" {
  type = string
}

variable "location" {
  type = string
}

variable "sku" {
  type = object({
    tier = string
    size = string
  })
  default = {
    tier = "Standard"
    size = "S1"
  }
}

# modules/app-service/main.tf
resource "azurerm_service_plan" "main" {
  name                = "asp-${var.name}"
  resource_group_name = var.resource_group_name
  location            = var.location
  os_type             = "Linux"
  sku_name            = var.sku.size
}

resource "azurerm_linux_web_app" "main" {
  name                = "app-${var.name}"
  resource_group_name = var.resource_group_name
  location            = var.location
  service_plan_id     = azurerm_service_plan.main.id

  site_config {
    always_on = var.sku.tier != "Free"
  }
}

# Usage in environment
module "api" {
  source = "../../modules/app-service"

  name                = "myapi-${var.environment}"
  resource_group_name = azurerm_resource_group.main.name
  location            = var.location
  sku = {
    tier = var.environment == "prod" ? "Premium" : "Standard"
    size = var.environment == "prod" ? "P1v3" : "S1"
  }
}

State Management

# backend.tf
terraform {
  backend "azurerm" {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "stterraformstate"
    container_name       = "tfstate"
    key                  = "myproject/dev/terraform.tfstate"
  }
}

State Best Practices:

  • ✅ Use remote state (never local for teams)
  • ✅ Enable state locking
  • ✅ Encrypt state at rest
  • ✅ Separate state per environment
  • ❌ Never commit .tfstate files
  • ❌ Never manually edit state

Data Sources

# Reference existing resources
data "azurerm_key_vault" "shared" {
  name                = "kv-shared-${var.environment}"
  resource_group_name = "rg-shared-${var.environment}"
}

data "azurerm_key_vault_secret" "db_password" {
  name         = "db-admin-password"
  key_vault_id = data.azurerm_key_vault.shared.id
}

# Use in resource
resource "azurerm_mssql_server" "main" {
  name                         = "sql-${var.project}-${var.environment}"
  administrator_login          = "sqladmin"
  administrator_login_password = data.azurerm_key_vault_secret.db_password.value
  # ...
}

Bicep Patterns (Azure)

Basic Structure

// main.bicep
targetScope = 'subscription'

@allowed(['dev', 'staging', 'prod'])
param environment string

param location string = 'eastus2'

var resourceGroupName = 'rg-myproject-${environment}'

resource rg 'Microsoft.Resources/resourceGroups@2023-07-01' = {
  name: resourceGroupName
  location: location
  tags: {
    Environment: environment
    ManagedBy: 'Bicep'
  }
}

module appService 'modules/app-service.bicep' = {
  scope: rg
  name: 'appServiceDeployment'
  params: {
    appName: 'app-myproject-${environment}'
    location: location
    sku: environment == 'prod' ? 'P1v3' : 'S1'
  }
}

output resourceGroupId string = rg.id
output appServiceUrl string = appService.outputs.defaultHostName

Module Pattern

// modules/app-service.bicep
@description('Name of the App Service')
param appName string

param location string = resourceGroup().location

@allowed(['F1', 'S1', 'P1v3'])
param sku string = 'S1'

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'asp-${appName}'
  location: location
  sku: {
    name: sku
  }
  kind: 'linux'
  properties: {
    reserved: true
  }
}

resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: appName
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      linuxFxVersion: 'NODE|20-lts'
      alwaysOn: sku != 'F1'
    }
  }
}

output defaultHostName string = webApp.properties.defaultHostName
output appServiceId string = webApp.id

Bicep vs Terraform for Azure

AspectBicepTerraform
Azure SupportDay-0Day-1 to Day-N
Multi-cloud
State ManagementAzure-managedSelf-managed
Learning CurveLowerModerate
Community ModulesLimitedExtensive
Type SafetyStrongModerate

Recommendation: Bicep for Azure-only; Terraform for multi-cloud or complex scenarios.


Pulumi Patterns

TypeScript Example

import * as pulumi from "@pulumi/pulumi";
import * as azure from "@pulumi/azure-native";

const config = new pulumi.Config();
const environment = config.require("environment");

// Resource Group
const resourceGroup = new azure.resources.ResourceGroup("rg", {
  resourceGroupName: `rg-myproject-${environment}`,
  location: "eastus2",
  tags: {
    Environment: environment,
    ManagedBy: "Pulumi",
  },
});

// App Service Plan
const appServicePlan = new azure.web.AppServicePlan("asp", {
  resourceGroupName: resourceGroup.name,
  kind: "Linux",
  reserved: true,
  sku: {
    name: environment === "prod" ? "P1v3" : "S1",
    tier: environment === "prod" ? "Premium" : "Standard",
  },
});

// Web App
const webApp = new azure.web.WebApp("app", {
  resourceGroupName: resourceGroup.name,
  serverFarmId: appServicePlan.id,
  siteConfig: {
    linuxFxVersion: "NODE|20-lts",
    alwaysOn: true,
  },
});

export const endpoint = pulumi.interpolate`https://${webApp.defaultHostName}`;

When to Use Pulumi

Good fit:

  • Team prefers TypeScript/Python/Go over HCL
  • Need complex logic (loops, conditionals, API calls)
  • Want type checking and IDE support
  • Building reusable libraries

Consider alternatives:

  • Simple infrastructure needs
  • Team experienced with Terraform
  • Need maximum community resources

Best Practices

Naming Conventions

Pattern: {resource-type}-{project}-{environment}-{region}-{instance}

Examples:
  rg-myproject-prod-eus2           (Resource Group)
  app-myproject-prod-eus2          (App Service)
  sql-myproject-prod-eus2          (SQL Server)
  kv-myproject-prod-eus2           (Key Vault)
  st-myproject-prod-eus2           (Storage - no hyphens)

Tagging Strategy

locals {
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "Terraform"
    CostCenter  = var.cost_center
    Owner       = var.owner_email
    CreatedDate = timestamp()
  }
}

resource "azurerm_resource_group" "main" {
  name     = "rg-${var.project}-${var.environment}"
  location = var.location
  tags     = local.common_tags
}

Secrets Management

❌ DON'T: Hard-code secrets in IaC
❌ DON'T: Store secrets in tfvars files
❌ DON'T: Commit secrets to version control

✅ DO: Use Key Vault / Secrets Manager
✅ DO: Reference secrets via data sources
✅ DO: Use CI/CD pipeline secrets
✅ DO: Use managed identities where possible

Environment Parity

┌─────────────────────────────────────────────────────────┐
│                    Same Code Base                       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   dev.tfvars      staging.tfvars      prod.tfvars      │
│   ┌─────────┐     ┌─────────┐        ┌─────────┐       │
│   │ SKU: S1 │     │ SKU: S1 │        │ SKU: P1v3│      │
│   │ Count:1 │     │ Count:2 │        │ Count:3  │      │
│   └─────────┘     └─────────┘        └─────────┘       │
│        │               │                  │             │
│        ▼               ▼                  ▼             │
│   ┌─────────┐     ┌─────────┐        ┌─────────┐       │
│   │   DEV   │     │ STAGING │        │  PROD   │       │
│   └─────────┘     └─────────┘        └─────────┘       │
│                                                         │
└─────────────────────────────────────────────────────────┘

Testing IaC

Static Analysis

# Terraform
terraform fmt -check
terraform validate
tflint
tfsec  # Security scanning
checkov  # Policy as code

# Bicep
az bicep build --file main.bicep  # Syntax check

Unit Testing (Terraform)

# tests/app_service_test.tftest.hcl
run "app_service_creates_correctly" {
  command = plan

  variables {
    environment = "dev"
    project     = "test"
  }

  assert {
    condition     = azurerm_linux_web_app.main.site_config[0].always_on == true
    error_message = "Always-on should be enabled"
  }
}

Integration Testing

# Deploy to ephemeral environment
terraform apply -auto-approve -var="environment=test-${BUILD_ID}"

# Run integration tests
npm test

# Destroy ephemeral environment
terraform destroy -auto-approve -var="environment=test-${BUILD_ID}"

CI/CD Patterns

GitHub Actions Workflow

name: Infrastructure

on:
  push:
    branches: [main]
    paths: ['infrastructure/**']
  pull_request:
    paths: ['infrastructure/**']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.7.0

      - name: Terraform Init
        run: terraform init
        working-directory: infrastructure/environments/prod
        env:
          ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_USE_OIDC: true

      - name: Terraform Plan
        run: terraform plan -out=tfplan
        working-directory: infrastructure/environments/prod

      - name: Upload Plan
        uses: actions/upload-artifact@v4
        with:
          name: tfplan
          path: infrastructure/environments/prod/tfplan

  apply:
    needs: plan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v6

      - uses: hashicorp/setup-terraform@v3

      - name: Download Plan
        uses: actions/download-artifact@v4
        with:
          name: tfplan
          path: infrastructure/environments/prod

      - name: Terraform Apply
        run: terraform apply -auto-approve tfplan
        working-directory: infrastructure/environments/prod

GitOps Flow

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Feature    │     │    Pull      │     │    Main      │
│   Branch     │ ──► │   Request    │ ──► │   Branch     │
└──────────────┘     └──────────────┘     └──────────────┘
       │                    │                    │
       ▼                    ▼                    ▼
  terraform plan      terraform plan       terraform apply
  (local preview)     (CI check)           (automated)

Common Patterns

Conditional Resources

# Terraform
resource "azurerm_application_insights" "main" {
  count = var.enable_monitoring ? 1 : 0

  name                = "appi-${var.project}-${var.environment}"
  resource_group_name = azurerm_resource_group.main.name
  location            = var.location
  application_type    = "web"
}

Dynamic Blocks

resource "azurerm_network_security_group" "main" {
  name                = "nsg-${var.project}-${var.environment}"
  resource_group_name = azurerm_resource_group.main.name
  location            = var.location

  dynamic "security_rule" {
    for_each = var.security_rules
    content {
      name                       = security_rule.value.name
      priority                   = security_rule.value.priority
      direction                  = security_rule.value.direction
      access                     = security_rule.value.access
      protocol                   = security_rule.value.protocol
      source_port_range          = security_rule.value.source_port_range
      destination_port_range     = security_rule.value.destination_port_range
      source_address_prefix      = security_rule.value.source_address_prefix
      destination_address_prefix = security_rule.value.destination_address_prefix
    }
  }
}

Resource Dependencies

# Implicit (recommended)
resource "azurerm_linux_web_app" "main" {
  service_plan_id = azurerm_service_plan.main.id  # Implicit dependency
}

# Explicit (when needed)
resource "azurerm_linux_web_app" "main" {
  depends_on = [azurerm_private_endpoint.sql]  # Wait for private endpoint
}

Anti-Patterns

❌ Monolithic Configuration

Problem: Single massive .tf file Solution: Split into logical modules and files

❌ Hard-coded Values

Problem: Values embedded in resources Solution: Use variables with defaults and tfvars

❌ No State Locking

Problem: Concurrent applies corrupt state Solution: Enable state locking (DynamoDB for S3, built-in for Azure)

❌ Manual Changes

Problem: Drift between code and reality Solution: Always change through code, use terraform import for existing resources

❌ Overly Generic Modules

Problem: Modules that try to do everything Solution: Purpose-built modules with sensible defaults


MCP Tool Integration

Required Extensions & MCP Servers

ComponentID / NamePurpose
VS Code Extensionms-azuretools.vscode-bicepBicep language support
VS Code Extensionhashicorp.terraformTerraform language support
VS Code Extensionms-azuretools.vscode-azure-github-copilotAzure Copilot integration
MCP Serverbicep-mcpBicep tools (AVM, schema, validation)
MCP Serverazure-mcpAzure architecture and deployment tools

Installation:

# VS Code Extensions
code --install-extension ms-azuretools.vscode-bicep
code --install-extension hashicorp.terraform
code --install-extension ms-azuretools.vscode-azure-github-copilot

# MCP Servers enabled via VS Code MCP gallery
# Settings: chat.mcp.gallery.enabled = true

Fallback Patterns (When MCP Unavailable)

MCP ToolFallback Approach
list_avm_metadataBrowse https://aka.ms/avm/modules
get_az_resource_type_schemaARM template reference or az rest API
get_bicep_best_practiceshttps://learn.microsoft.com/azure/azure-resource-manager/bicep/best-practices
get_bicep_file_diagnosticsVS Code Bicep extension or bicep build CLI
cloudarchitectAzure Architecture Center + WAF Assessment (https://aka.ms/waf-assessment)
documentationhttps://learn.microsoft.com/azure/architecture

Terraform Fallbacks (no MCP yet):

# Terraform validation
terraform validate
terraform fmt -check

# Provider docs
terraform providers schema -json

# Static analysis
tflint
tfsec
checkov -d .

Available IaC MCP Tools

the AI assistant has access to Bicep MCP tools for enhanced infrastructure as code capabilities:

ToolPurpose
mcp_bicep_list_avm_metadataBrowse 328 Azure Verified Modules
mcp_bicep_get_az_resource_type_schemaGet resource type properties and schema
mcp_bicep_get_bicep_best_practicesCurrent Bicep coding best practices
mcp_bicep_get_bicep_file_diagnosticsValidate Bicep files, find errors
mcp_bicep_format_bicep_fileAuto-format Bicep code
mcp_bicep_decompile_arm_template_fileConvert ARM JSON → Bicep
mcp_bicep_decompile_arm_parameters_fileConvert parameters.json → .bicepparam

Azure Architecture Tools

ToolPurpose
mcp_azure_mcp_cloudarchitectInteractive architecture design aligned with WAF
mcp_azure_mcp_documentationSearch Azure docs and best practices
mcp_azure_mcp_get_bestpracticesCode generation and deployment patterns

Workflow: MCP-Enhanced IaC

1. Architecture Design
   └─ mcp_azure_mcp_cloudarchitect → Requirements → Component design

2. Module Discovery
   └─ mcp_bicep_list_avm_metadata → Find production-ready modules

3. Schema Lookup
   └─ mcp_bicep_get_az_resource_type_schema → Exact properties

4. Code Generation
   └─ mcp_bicep_get_bicep_best_practices → Write clean code

5. Validation
   └─ mcp_bicep_get_bicep_file_diagnostics → Fix errors early

6. Deployment
   └─ mcp_azure_mcp_deploy → Automated deployment

When to Use MCP Tools

ScenarioTool
"What modules exist for X?"list_avm_metadata
"What properties does X support?"get_az_resource_type_schema
"Review my Bicep file"get_bicep_file_diagnostics
"Convert ARM to Bicep"decompile_arm_template_file
"Design infrastructure from scratch"cloudarchitect

Related Skill: See bicep-avm-mastery for deep Bicep patterns and AVM guidance.


Activation Triggers

  • "infrastructure as code", "IaC"
  • "Terraform", "Bicep", "Pulumi", "CloudFormation"
  • "provision infrastructure", "deploy infrastructure"
  • "HCL", "tfvars", "terraform.tfstate"
  • "ARM template", "CDK"
  • "GitOps", "infrastructure pipeline"
  • "MCP Bicep", "AVM modules", "Azure Verified Modules"
  • "convert ARM to Bicep", "validate Bicep"

Quick Reference

IaC Checklist

  • Use remote state with locking
  • Implement consistent naming conventions
  • Apply tagging strategy for all resources
  • Store secrets in Key Vault / Secrets Manager
  • Use modules for reusable components
  • Run static analysis (tflint, tfsec)
  • Set up CI/CD pipeline with plan/apply
  • Document module inputs and outputs
  • Test with ephemeral environments
  • Enable drift detection

Command Reference

# Terraform
terraform init          # Initialize backend and providers
terraform plan          # Preview changes
terraform apply         # Apply changes
terraform destroy       # Tear down infrastructure
terraform import        # Import existing resource
terraform state list    # List resources in state
terraform fmt           # Format code

# Bicep
az bicep build          # Compile to ARM
az deployment sub create --location eastus2 --template-file main.bicep
az deployment group create --resource-group rg-name --template-file main.bicep

Infrastructure as Code skill — Reliable, repeatable infrastructure through code | MCP-Enhanced: Yes | Updated: 2026-02-14


Keep looking

Skills are one crate of 326,861. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.