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.
|
||||
Reference in New Issue
Block a user