Implement security best practices including secrets management, policy as code, and compliance scanning
View on GitHubpluginagentmarketplace/custom-plugin-terraform
terraform-assistant
January 20, 2026
Select agents to install to:
npx add-skill https://github.com/pluginagentmarketplace/custom-plugin-terraform/blob/main/skills/terraform-security/SKILL.md -a claude-code --skill terraform-securityInstallation paths:
.claude/skills/terraform-security/# Terraform Security Skill
Production security patterns for Terraform including secrets, policies, and compliance.
## Secrets Management
### HashiCorp Vault
```hcl
provider "vault" {
address = var.vault_address
}
data "vault_kv_secret_v2" "db" {
mount = "secret"
name = "database/prod"
}
resource "aws_db_instance" "main" {
username = data.vault_kv_secret_v2.db.data["username"]
password = data.vault_kv_secret_v2.db.data["password"]
}
```
### AWS Secrets Manager
```hcl
resource "aws_secretsmanager_secret" "db" {
name = "${var.project}/database"
recovery_window_in_days = 30
}
data "aws_secretsmanager_secret_version" "db" {
secret_id = aws_secretsmanager_secret.db.id
}
locals {
db_credentials = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)
}
```
### Azure Key Vault
```hcl
data "azurerm_key_vault_secret" "db_password" {
name = "db-password"
key_vault_id = azurerm_key_vault.main.id
}
resource "azurerm_mssql_server" "main" {
administrator_login_password = data.azurerm_key_vault_secret.db_password.value
}
```
## Policy as Code
### Sentinel (Terraform Cloud)
```python
# restrict-instance-types.sentinel
import "tfplan/v2" as tfplan
allowed_types = ["t3.micro", "t3.small", "t3.medium"]
main = rule {
all tfplan.resource_changes as _, rc {
rc.type is "aws_instance" implies
rc.change.after.instance_type in allowed_types
}
}
```
### OPA/Conftest
```rego
# policy/terraform.rego
package terraform.security
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
resource.change.after.acl == "public-read"
msg := sprintf("Public S3 bucket: %s", [resource.address])
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_db_instance"
resource.change.after.storage_encrypted != true
msg := sprintf("Unencrypted RDS: %s", [resource.address])
}
```
## Security Scanning
### Pre-commit Configuration
```yaml
# .pre-commit-config.yam