iTranslated by AI
Infrastructure Engineers Want to Try Cline Too!
Motivation
Recently, Cline has been making a lot of noise in the community, and that's what motivated me to try it out.
Since I usually focus on infrastructure rather than application development, I decided to try writing Terraform with Cline.
I wasn't picky about the topic, so I asked it to create a "Basic web application" from the Azure Architecture Center.
Result
I was able to create it.

The models used were as follows, and it generated the code for about 2 dollars.
| Mode | Model |
|---|---|
| Plan | claude3.7-sonnet |
| Act | gemini-2.0-flash-001* |
*I switched to Claude briefly because I hit the rate limit on the free tier.
The folder structure of the generated code looks like this.

What I Did
Creating clinerules
I created clinerules to provide Cline with module separation, naming conventions, test plans, and other guidelines.
These rules were generated by feeding Claude the official Terraform Style Guide and Google Cloud's Best practices for general style and structure.
clinerules
# Terraform Coding Practices
## Principles
### DRY Principle (Don't Repeat Yourself)
- Leverage local variables to avoid repetition.
- Abstract common code using modules (Create modules per service, e.g., azurevm, appservice, etc.).
- Use variables and outputs appropriately.
- Use for_each and count to group similar resources.
### Readability and Maintainability
- Consistent code formatting.
- Clear naming conventions.
- Proper comments and documentation.
- Module separation and reuse.
## Implementation Patterns
### File Structure
├── env/ # Environment-specific settings
│ ├── dev/
│ │ └── terraform.tfvars # Development environment variables
│ ├── test/
│ │ └── terraform.tfvars # Test environment variables
│ └── prod/
│ └── terraform.tfvars # Production environment variables
├── main.tf # Resource definitions
├── variables.tf # Input variables
├── outputs.tf # Output variables
├── locals.tf # Local variables
├── providers.tf # Provider configuration
├── backend.tf # Backend configuration
├── terraform.tf # Settings for Terraform version, etc.
├── README.md # Project description and usage
└── modules/ # Reusable modules
└── <module_name>/
├── main.tf
├── variables.tf
└── outputs.tf
### Resource Naming
Give resources readable and consistent names. Separate words with underscores and do not include the resource type in the resource identifier.
# Bad Example
resource "azurerm_virtual_network" "vnet-prod-eastus" {...}
# Good Example
resource "azurerm_virtual_network" "sys_vnet" {...}
### Tagging
Always set the following tags on Azure resources. Set an appropriate name for each resource in the Name tag:
resource "azurerm_resource_group" "example" {
# ...
tags = {
Name = "example-resource-group" # Appropriate name for each resource
System = var.system_name
Env = var.environment
}
}
resource "azurerm_virtual_network" "example" {
# ...
tags = {
Name = "example-vnet" # Appropriate name for each resource
System = var.system_name
Env = var.environment
}
}
### Variable Definition
Always include a type and description for all variables. Set appropriate default values for optional variables.
variable "location" {
type = string
description = "The Azure region where resources will be created"
default = "eastus"
}
variable "environment" {
type = string
description = "Environment name (dev, test, prod)"
validation {
condition = contains(["dev", "test", "prod"], var.environment)
error_message = "Environment must be one of: dev, test, prod."
}
}
### Output Variables
Always include a description for output variables.
output "resource_group_id" {
description = "The ID of the created resource group"
value = azurerm_resource_group.main.id
}
### Local Variables
Use local variables to define expressions or values that are used multiple times within the code.
locals {
name_suffix = "${var.environment}-${var.location}"
resource_prefix = "${var.system_name}-${local.name_suffix}"
}
### Secret Management
Never hardcode secret information (passwords, API keys, connection strings, etc.) in the code. Use the following methods:
- Generate random characters during resource construction and store them in Azure Key Vault.
# Bad Example - Hardcoded
resource "azurerm_sql_server" "example" {
administrator_login_password = "SuperSecret123!" # Should be avoided
}
# Good Example
resource "azurerm_sql_server" "example" {
administrator_login_password = var.sql_admin_password # Pass as a variable
}
### Project-Specific Information
system_name should store "sys".
The resource naming convention should be sys_[environment abbreviation]_[resource abbreviation]_[role].
Please cite resource abbreviations from the following document:
https://learn.microsoft.com/ja-jp/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations
## How to Use Terraform
### AzureRM Provider Configuration
# providers.tf
provider "azurerm" {
features {}
}
# terraform.tf
Set the version of azurerm to the latest major version.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0.0"
}
}
}
### Using for_each and count
Use for_each or count when creating multiple similar resources.
# Example of for_each
variable "subnets" {
type = map(object({
address_prefix = string
service_endpoints = list(string)
}))
default = {
web = {
address_prefix = "10.0.1.0/24"
service_endpoints = ["Microsoft.Web"]
},
app = {
address_prefix = "10.0.2.0/24"
service_endpoints = ["Microsoft.Sql"]
},
data = {
address_prefix = "10.0.3.0/24"
service_endpoints = ["Microsoft.Sql", "Microsoft.Storage"]
}
}
}
resource "azurerm_subnet" "example" {
for_each = var.subnets
name = each.key
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [each.value.address_prefix]
service_endpoints = each.value.service_endpoints
}
## Module Design
### Basic Module Structure
modules/
└── virtual_machine/
├── main.tf # Resource definitions
├── variables.tf # Input variables
└── outputs.tf # Output variables
### Calling Modules
module "web_server" {
source = "./modules/virtual_machine"
name = "web"
vm_size = "Standard_B2s"
admin_username = var.admin_username
location = var.location
resource_group_name = azurerm_resource_group.main.name
subnet_id = azurerm_subnet.main.id
system_name = var.system_name
environment = var.environment
}
## Code Quality and Workflow
### terraform fmt
Always run `terraform fmt` before committing to maintain consistent code formatting.
### terraform validate
Use `terraform validate` to detect syntax errors and common issues.
### Security Check
Use `checkov` to scan for Infrastructure as Code security and compliance best practices.
checkov -d .
### .gitignore
Exclude the following files from version control:
.terraform/
.terraform.lock.hcl
### Implementation Steps
1. **Start with Design**
- Identify required resources
- Plan environment variables and module design
2. **Incremental Implementation**
- Start with basic infrastructure
- Add security settings
- Add application resources
3. **Ensure Code Quality**
- Format with terraform fmt
- Validate with terraform validate
- Security check with checkov
- Confirm content with terraform plan
4. **Create Documentation**
- Describe usage in README.md
- Provide comprehensive variable descriptions
- Provide examples
Requesting from Cline
After finishing the initial setup of Cline, it was time to execute. I was curious about how vague a request it could handle, so the prompt was very rough.
I provided a screenshot of the architecture diagram for a basic web application and made a casual request to create it accordingly.

(Although I wrote "Speak in Japanese" in the system prompt, it occasionally spoke in English, so I included it in the prompt as well.)
It formulated an execution plan in Plan mode, started writing code when switched to Act, and once the code was written, it even ran terraform init/plan/apply.
Seeing Cline running commands in the local environment and troubleshooting by looking over the project when an error occurred really made me feel like we've entered a new era...!
What Didn't Go Well
While I was amazed by Cline, there were a few points that didn't go as expected, perhaps due to my own lack of "Cline skills." I'll share them here. I would appreciate any comments if you have suggestions for improvement.
It doesn't read clinerules properly
After submitting the initial prompt, it reads clinerules as shown below.

Then, the results of the plan were displayed, but the file structure was different from what was in clinerules...
The modules weren't separated either...

In addition, despite instructions to generate secrets randomly and store them in Key Vault, it asked for information from the user...

However, I was able to improve the situation by pointing out the incorrect parts and instructing it to re-read them properly.
I will continue to explore whether there are ways to write rules with more mandatory force.
Unable to intelligently incorporate checkov results
I've set it up to check the quality of the generated code with checkov.
This time, about 20 items failed, and Cline proactively went about fixing those failures.
I was watching, thinking "That's impressive," but upon closer look, it was trying to create a Private Endpoint even though the architecture didn't have a Vnet, or it was blocking public access indiscriminately...
This might be related to the performance of the model used in Act mode, but I would be happy if it could behave in a way where it understands the architecture, makes an initial judgment on whether to incorporate the findings, and then asks for direction.
Summary
These were my thoughts after trying out Cline for the first time.
As for the positive aspects, its ability to generate reasonably functional code from vague instructions and even detect and fix errors lived up to its reputation, and I truly felt its potential!
On the other hand, there were areas where there is still room for improvement, such as adherence to clinerules and the appropriate incorporation of checkov results.
I plan to experiment with prompts and clinerules to explore ways to set more mandatory rules and create mechanisms that allow for judgments based on an understanding of the architecture.
Discussion