A Terraform provider for Dokploy
Plugin-framework provider covering projects, environments, applications, Compose stacks, managed databases, domains, mounts, ports, redirects, basic auth, registries, SSH keys, certificates and backup destinations, over Dokploy's tRPC-over-REST API. The shim package exposes the provider to other Go modules, which is how pulumi-dokploy bridges it.
This commit is contained in:
164
.agents/skills/terraform-style-guide/SECURITY.md
Normal file
164
.agents/skills/terraform-style-guide/SECURITY.md
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
name: terraform-style-guide-security
|
||||
description: Generate Terraform HCL code following HashiCorp's security practices
|
||||
---
|
||||
|
||||
# Terraform Style Guide - Security
|
||||
|
||||
When generating code, apply security hardening:
|
||||
|
||||
- Enable encryption at rest by default
|
||||
- Configure private networking where applicable
|
||||
- Apply principle of least privilege for security groups
|
||||
- Enable logging and monitoring
|
||||
- Never hardcode credentials or secrets
|
||||
- Mark sensitive outputs with `sensitive = true`
|
||||
- Use `ephemeral` resources and write-only attributes
|
||||
for sensitive data when possible
|
||||
|
||||
## Example: Secure S3 Bucket
|
||||
|
||||
```hcl
|
||||
resource "aws_s3_bucket" "data" {
|
||||
bucket = "${var.project}-${var.environment}-data"
|
||||
tags = local.common_tags
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "data" {
|
||||
bucket = aws_s3_bucket.data.id
|
||||
|
||||
versioning_configuration {
|
||||
status = "Enabled"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
|
||||
bucket = aws_s3_bucket.data.id
|
||||
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "aws:kms"
|
||||
kms_master_key_id = aws_kms_key.s3.arn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "data" {
|
||||
bucket = aws_s3_bucket.data.id
|
||||
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
```
|
||||
|
||||
## Ephemeral resources
|
||||
|
||||
Ephemeral resources prevent sensitive data being stored in state.
|
||||
For more information on ephemeral resources, see the
|
||||
[Terraform documentation](https://developer.hashicorp.com/terraform/language/block/ephemeral).
|
||||
|
||||
Before you generate code for an ephemeral resource, check that the Terraform
|
||||
version is greater than or equal to 1.11.0.
|
||||
|
||||
Then, follow this priority order for managing sensitive attributes:
|
||||
|
||||
1. **First priority: Native secrets manager integration**
|
||||
If a resource has the ability to automatically manage a sensitive attribute by
|
||||
storing it in a secrets manager (e.g., AWS Secrets Manager, Azure Key Vault),
|
||||
use that configuration. This is the preferred approach.
|
||||
|
||||
```hcl
|
||||
# Bad
|
||||
resource "aws_rds_cluster" "example" {
|
||||
cluster_identifier = "example"
|
||||
database_name = "test"
|
||||
master_username = "test"
|
||||
master_password = var.db_master_password
|
||||
}
|
||||
|
||||
# Good, managed by AWS Secrets Manager by default
|
||||
resource "aws_rds_cluster" "test" {
|
||||
cluster_identifier = "example"
|
||||
database_name = "test"
|
||||
manage_master_user_password = true
|
||||
master_username = "test"
|
||||
}
|
||||
```
|
||||
|
||||
2. **Second priority: Write-only attributes with ephemeral resources**
|
||||
If a resource has a write-only attribute but no native secrets manager integration,
|
||||
use an `ephemeral` resource for the sensitive data and pass that to the write-only
|
||||
attribute. Default the write-only version to 1.
|
||||
|
||||
```hcl
|
||||
# Bad
|
||||
resource "random_password" "password" {
|
||||
length = 16
|
||||
special = true
|
||||
override_special = "!#$%&*()-_=+[]{}<>:?"
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "example" {
|
||||
mount = vault_mount.kvv2.path
|
||||
name = "secret"
|
||||
|
||||
data_json = jsonencode(
|
||||
{
|
||||
password = "${random_password.password.result}",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
# Good
|
||||
ephemeral "random_password" "password" {
|
||||
length = 16
|
||||
special = true
|
||||
override_special = "!#$%&*()-_=+[]{}<>:?"
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "example" {
|
||||
mount = vault_mount.kvv2.path
|
||||
name = "secret"
|
||||
|
||||
data_json_wo = jsonencode(
|
||||
{
|
||||
password = "${ephemeral.random_password.password.result}",
|
||||
}
|
||||
)
|
||||
data_json_wo_version = 1
|
||||
}
|
||||
```
|
||||
|
||||
If you need to retrieve a secret from a secrets manager to pass
|
||||
to a resource, use the `ephemeral` version of the resource to
|
||||
retrieve the secret and pass it to another resource.
|
||||
|
||||
```hcl
|
||||
# Good
|
||||
ephemeral "vault_kv_secret_v2" "db_secret" {
|
||||
mount = vault_mount.kvv2.path
|
||||
mount_id = vault_mount.kvv2.id
|
||||
name = vault_kv_secret_v2.db_root.name
|
||||
}
|
||||
|
||||
resource "vault_database_secret_backend_connection" "postgres" {
|
||||
backend = vault_mount.db.path
|
||||
name = "postrgres-db"
|
||||
allowed_roles = ["*"]
|
||||
|
||||
postgresql {
|
||||
connection_url = "postgresql://{{username}}:{{password}}@localhost:5432/postgres"
|
||||
password_authentication = ""
|
||||
username = "postgres"
|
||||
password_wo = tostring(ephemeral.vault_kv_secret_v2.db_secret.data.password)
|
||||
password_wo_version = 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Last resort: Regular resources**
|
||||
Only use a regular resource that has sensitive data written to state if neither of the above
|
||||
options are available, resource does not offer a write-only attribute or ephemeral resource
|
||||
alternative, or the Terraform version is less than 1.11.0.
|
||||
314
.agents/skills/terraform-style-guide/SKILL.md
Normal file
314
.agents/skills/terraform-style-guide/SKILL.md
Normal file
@@ -0,0 +1,314 @@
|
||||
---
|
||||
name: terraform-style-guide
|
||||
description: Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.
|
||||
---
|
||||
|
||||
# Terraform Style Guide
|
||||
|
||||
Generate and maintain Terraform code following HashiCorp's official style conventions and best practices.
|
||||
|
||||
**Reference:** [HashiCorp Terraform Style Guide](https://developer.hashicorp.com/terraform/language/style)
|
||||
|
||||
## Code Generation Strategy
|
||||
|
||||
When generating Terraform code:
|
||||
|
||||
1. Start with provider configuration and version constraints
|
||||
2. Create data sources before dependent resources
|
||||
3. Build resources in dependency order
|
||||
4. Add outputs for key resource attributes
|
||||
5. Use variables for all configurable values
|
||||
|
||||
## File Organization
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `terraform.tf` | Terraform and provider version requirements |
|
||||
| `providers.tf` | Provider configurations |
|
||||
| `main.tf` | Primary resources and data sources |
|
||||
| `variables.tf` | Input variable declarations (alphabetical) |
|
||||
| `outputs.tf` | Output value declarations (alphabetical) |
|
||||
| `locals.tf` | Local value declarations |
|
||||
|
||||
### Example Structure
|
||||
|
||||
```hcl
|
||||
# terraform.tf
|
||||
terraform {
|
||||
required_version = ">= 1.14"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# variables.tf
|
||||
variable "environment" {
|
||||
description = "Target deployment environment"
|
||||
type = string
|
||||
|
||||
validation {
|
||||
condition = contains(["dev", "staging", "prod"], var.environment)
|
||||
error_message = "Environment must be dev, staging, or prod."
|
||||
}
|
||||
}
|
||||
|
||||
# locals.tf
|
||||
locals {
|
||||
common_tags = {
|
||||
Environment = var.environment
|
||||
ManagedBy = "Terraform"
|
||||
}
|
||||
}
|
||||
|
||||
# main.tf
|
||||
resource "aws_vpc" "main" {
|
||||
cidr_block = var.vpc_cidr
|
||||
enable_dns_hostnames = true
|
||||
|
||||
tags = merge(local.common_tags, {
|
||||
Name = "${var.project_name}-${var.environment}-vpc"
|
||||
})
|
||||
}
|
||||
|
||||
# outputs.tf
|
||||
output "vpc_id" {
|
||||
description = "ID of the created VPC"
|
||||
value = aws_vpc.main.id
|
||||
}
|
||||
```
|
||||
|
||||
## Code Formatting
|
||||
|
||||
### Indentation and Alignment
|
||||
|
||||
- Use **two spaces** per nesting level (no tabs)
|
||||
- Align equals signs for consecutive arguments
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "web" {
|
||||
ami = "ami-0c55b159cbfafe1f0"
|
||||
instance_type = "t2.micro"
|
||||
subnet_id = "subnet-12345678"
|
||||
|
||||
tags = {
|
||||
Name = "web-server"
|
||||
Environment = "production"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Block Organization
|
||||
|
||||
Arguments precede blocks, with meta-arguments first:
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "example" {
|
||||
# Meta-arguments
|
||||
count = 3
|
||||
|
||||
# Arguments
|
||||
ami = "ami-0c55b159cbfafe1f0"
|
||||
instance_type = "t2.micro"
|
||||
|
||||
# Blocks
|
||||
root_block_device {
|
||||
volume_size = 20
|
||||
}
|
||||
|
||||
# Lifecycle last
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- Use **lowercase with underscores** for all names
|
||||
- Use **descriptive nouns** excluding the resource type
|
||||
- Be specific and meaningful
|
||||
- Resource names must be singular, not plural
|
||||
- Default to `main` for resources where a specific descriptive name is redundant or unavailable, provided only one instance exists
|
||||
|
||||
```hcl
|
||||
# Bad
|
||||
resource "aws_instance" "webAPI-aws-instance" {}
|
||||
resource "aws_instance" "web_apis" {}
|
||||
variable "name" {}
|
||||
|
||||
# Good
|
||||
resource "aws_instance" "web_api" {}
|
||||
resource "aws_vpc" "main" {}
|
||||
variable "application_name" {}
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
Every variable must include `type` and `description`:
|
||||
|
||||
```hcl
|
||||
variable "instance_type" {
|
||||
description = "EC2 instance type for the web server"
|
||||
type = string
|
||||
default = "t2.micro"
|
||||
|
||||
validation {
|
||||
condition = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type)
|
||||
error_message = "Instance type must be t2.micro, t2.small, or t2.medium."
|
||||
}
|
||||
}
|
||||
|
||||
variable "database_password" {
|
||||
description = "Password for the database admin user"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
```
|
||||
|
||||
## Outputs
|
||||
|
||||
Every output must include `description`:
|
||||
|
||||
```hcl
|
||||
output "instance_id" {
|
||||
description = "ID of the EC2 instance"
|
||||
value = aws_instance.web.id
|
||||
}
|
||||
|
||||
output "database_password" {
|
||||
description = "Database administrator password"
|
||||
value = aws_db_instance.main.password
|
||||
sensitive = true
|
||||
}
|
||||
```
|
||||
|
||||
## Dynamic Resource Creation
|
||||
|
||||
### Prefer for_each over count
|
||||
|
||||
```hcl
|
||||
# Bad - count for multiple resources
|
||||
resource "aws_instance" "web" {
|
||||
count = var.instance_count
|
||||
tags = { Name = "web-${count.index}" }
|
||||
}
|
||||
|
||||
# Good - for_each with named instances
|
||||
variable "instance_names" {
|
||||
type = set(string)
|
||||
default = ["web-1", "web-2", "web-3"]
|
||||
}
|
||||
|
||||
resource "aws_instance" "web" {
|
||||
for_each = var.instance_names
|
||||
tags = { Name = each.key }
|
||||
}
|
||||
```
|
||||
|
||||
### count for Conditional Creation
|
||||
|
||||
```hcl
|
||||
resource "aws_cloudwatch_metric_alarm" "cpu" {
|
||||
count = var.enable_monitoring ? 1 : 0
|
||||
|
||||
alarm_name = "high-cpu-usage"
|
||||
threshold = 80
|
||||
}
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
Refer to SECURITY.md. It includes guidance on encrypting resources,
|
||||
preventing sensitive data in state, and secure configurations.
|
||||
|
||||
## Version Pinning
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_version = ">= 1.14"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the latest major version of each provider and the latest minor version of
|
||||
Terraform, unless otherwise constrained by a dependency lock file or by other
|
||||
modules used by the configuration.
|
||||
|
||||
**Version constraint operators:**
|
||||
- `= 1.0.0` - Exact version
|
||||
- `>= 1.0.0` - Greater than or equal
|
||||
- `~> 1.0` - Allow rightmost component to increment
|
||||
- `>= 1.0, < 2.0` - Version range
|
||||
|
||||
## Provider Configuration
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-west-2"
|
||||
|
||||
default_tags {
|
||||
tags = {
|
||||
ManagedBy = "Terraform"
|
||||
Project = var.project_name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Aliased provider for multi-region
|
||||
provider "aws" {
|
||||
alias = "east"
|
||||
region = "us-east-1"
|
||||
}
|
||||
```
|
||||
|
||||
## Version Control
|
||||
|
||||
**Never commit:**
|
||||
- `terraform.tfstate`, `terraform.tfstate.backup`
|
||||
- `.terraform/` directory
|
||||
- `*.tfplan`
|
||||
- `.tfvars` files with sensitive data
|
||||
|
||||
**Always commit:**
|
||||
- All `.tf` configuration files
|
||||
- `.terraform.lock.hcl` (dependency lock file)
|
||||
|
||||
## Validation Tools
|
||||
|
||||
Run before committing:
|
||||
|
||||
```bash
|
||||
terraform fmt -recursive
|
||||
terraform validate
|
||||
```
|
||||
|
||||
Additional tools:
|
||||
- `tflint` - Linting and best practices
|
||||
- `checkov` / `tfsec` - Security scanning
|
||||
|
||||
## Code Review Checklist
|
||||
|
||||
- [ ] Code formatted with `terraform fmt`
|
||||
- [ ] Configuration validated with `terraform validate`
|
||||
- [ ] Files organized according to standard structure
|
||||
- [ ] All variables have type and description
|
||||
- [ ] All outputs have descriptions
|
||||
- [ ] Resource names use descriptive nouns with underscores
|
||||
- [ ] Version constraints pinned explicitly
|
||||
- [ ] Sensitive values marked with `sensitive = true`
|
||||
- [ ] No hardcoded credentials or secrets
|
||||
- [ ] Security best practices applied
|
||||
|
||||
---
|
||||
|
||||
*Based on: [HashiCorp Terraform Style Guide](https://developer.hashicorp.com/terraform/language/style)*
|
||||
Reference in New Issue
Block a user