Add comprehensive README and update module documentation
This commit is contained in:
parent
53459fa995
commit
6edad4aaf2
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
323
README.md
Normal file → Executable file
323
README.md
Normal file → Executable file
@ -1,6 +1,321 @@
|
||||
# S3 Backend Module
|
||||
This module will deply an s3 remote backend for Terraform
|
||||
# Terraform AWS S3 Backend Module
|
||||
|
||||
Locking is handled by a serverless provisioned DynamoDB Table
|
||||
All contents of the s3 bucket is encrypted via a KMS key and privileges are set in such a way that it only has the least ammount of privileges.
|
||||
## Overview
|
||||
|
||||
This Terraform module creates a secure S3 backend for Terraform state management with DynamoDB state locking. It provides encrypted state storage, version control, and concurrent access protection using AWS best practices.
|
||||
|
||||
## Features
|
||||
|
||||
- S3 bucket with versioning enabled
|
||||
- KMS encryption for state files
|
||||
- DynamoDB table for state locking
|
||||
- IAM role for secure access
|
||||
- Public access blocking
|
||||
- Resource grouping for easy management
|
||||
- Configurable force destroy option
|
||||
- Least privilege IAM policies
|
||||
|
||||
## Resources Created
|
||||
|
||||
### Storage
|
||||
- S3 Bucket with:
|
||||
- Versioning enabled
|
||||
- KMS encryption
|
||||
- Public access blocked
|
||||
- Unique naming with random suffix
|
||||
|
||||
### State Locking
|
||||
- DynamoDB Table with:
|
||||
- Pay-per-request billing
|
||||
- LockID hash key
|
||||
|
||||
### Security
|
||||
- KMS Key for encryption
|
||||
- IAM Role for state access
|
||||
- IAM Policy with minimal permissions
|
||||
- Resource Group for organization
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
|
||||
```hcl
|
||||
module "terraform_backend" {
|
||||
source = "git@github.com:webuildyourcloud/terraform-aws-s3-backend.git"
|
||||
|
||||
namespace = "myorg-prod"
|
||||
force_destroy_state = false
|
||||
}
|
||||
```
|
||||
|
||||
### With Custom IAM Principals
|
||||
|
||||
```hcl
|
||||
module "terraform_backend" {
|
||||
source = "git@github.com:webuildyourcloud/terraform-aws-s3-backend.git"
|
||||
|
||||
namespace = "myorg-dev"
|
||||
force_destroy_state = true
|
||||
|
||||
principle_arns = [
|
||||
"arn:aws:iam::123456789012:user/terraform",
|
||||
"arn:aws:iam::123456789012:role/TerraformExecutionRole"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### For CI/CD Pipeline
|
||||
|
||||
```hcl
|
||||
module "terraform_backend" {
|
||||
source = "git@github.com:webuildyourcloud/terraform-aws-s3-backend.git"
|
||||
|
||||
namespace = "cicd-terraform"
|
||||
force_destroy_state = false
|
||||
|
||||
principle_arns = [
|
||||
"arn:aws:iam::123456789012:role/GitHubActionsRole",
|
||||
"arn:aws:iam::123456789012:role/JenkinsRole"
|
||||
]
|
||||
}
|
||||
|
||||
# Output the backend configuration
|
||||
output "terraform_backend_config" {
|
||||
value = module.terraform_backend.config
|
||||
}
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|----------|
|
||||
| namespace | Project namespace for unique resource naming | `string` | `"s3backend"` | no |
|
||||
| principle_arns | List of principal ARNs allowed to assume the IAM role | `list(string)` | `null` | no |
|
||||
| force_destroy_state | Force destroy the S3 bucket containing state files | `bool` | `true` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| config | Complete backend configuration object containing bucket, region, role_arn, and dynamodb_table |
|
||||
|
||||
The `config` output provides:
|
||||
```hcl
|
||||
{
|
||||
bucket = "namespace-randomstring-state-bucket"
|
||||
region = "current-region"
|
||||
role_arn = "arn:aws:iam::account-id:role/namespace-randomstring-tf-assume-role"
|
||||
dynamodb_table = "namespace-randomstring-state-lock"
|
||||
}
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 0.15 |
|
||||
| aws | ~> 3.28 |
|
||||
| random | ~> 3.0 |
|
||||
|
||||
## Configuring Terraform Backend
|
||||
|
||||
After creating the backend, configure Terraform to use it:
|
||||
|
||||
### Step 1: Create the Backend Resources
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform apply
|
||||
```
|
||||
|
||||
### Step 2: Note the Outputs
|
||||
|
||||
```bash
|
||||
terraform output config
|
||||
```
|
||||
|
||||
### Step 3: Configure Your Terraform Backend
|
||||
|
||||
Create or update `backend.tf`:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "myorg-prod-xyz123-state-bucket"
|
||||
key = "path/to/statefile.tfstate"
|
||||
region = "us-east-1"
|
||||
dynamodb_table = "myorg-prod-xyz123-state-lock"
|
||||
encrypt = true
|
||||
role_arn = "arn:aws:iam::123456789012:role/myorg-prod-xyz123-tf-assume-role"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Migrate Existing State (if applicable)
|
||||
|
||||
```bash
|
||||
terraform init -migrate-state
|
||||
```
|
||||
|
||||
## IAM Permissions
|
||||
|
||||
The module creates an IAM role with the following permissions:
|
||||
|
||||
### S3 Permissions
|
||||
- `s3:ListBucket` - List bucket contents
|
||||
- `s3:GetObject` - Read state files
|
||||
- `s3:PutObject` - Write state files
|
||||
- `s3:DeleteObject` - Delete old state versions
|
||||
|
||||
### DynamoDB Permissions
|
||||
- `dynamodb:GetItem` - Read lock status
|
||||
- `dynamodb:PutItem` - Acquire lock
|
||||
- `dynamodb:DeleteItem` - Release lock
|
||||
|
||||
## Security Features
|
||||
|
||||
### Encryption at Rest
|
||||
All state files are encrypted using AWS KMS with a dedicated encryption key.
|
||||
|
||||
### Encryption in Transit
|
||||
All S3 API calls use HTTPS (TLS/SSL).
|
||||
|
||||
### Public Access Blocked
|
||||
The module explicitly blocks:
|
||||
- Public ACLs
|
||||
- Public bucket policies
|
||||
- Public object access
|
||||
- Public bucket access
|
||||
|
||||
### Versioning
|
||||
S3 bucket versioning is enabled to:
|
||||
- Protect against accidental deletion
|
||||
- Allow state recovery
|
||||
- Maintain state history
|
||||
|
||||
### State Locking
|
||||
DynamoDB table prevents:
|
||||
- Concurrent state modifications
|
||||
- State corruption
|
||||
- Race conditions
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **Unique Naming**: The module generates unique bucket names using random strings
|
||||
2. **Bootstrapping**: This module must be deployed without a backend initially
|
||||
3. **State Migration**: After creation, migrate your state to the new backend
|
||||
4. **Force Destroy**: Set `force_destroy_state = false` for production
|
||||
5. **IAM Principals**: If not specified, defaults to the current caller's ARN
|
||||
6. **KMS Costs**: KMS key incurs monthly charges
|
||||
7. **Region Locked**: Backend resources are created in the current region
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Separate Backends**: Use different backends for different environments
|
||||
2. **Least Privilege**: Only grant access to necessary IAM principals
|
||||
3. **State File Paths**: Use descriptive key paths (e.g., `env/prod/vpc/terraform.tfstate`)
|
||||
4. **Backup**: Enable S3 Cross-Region Replication for critical state files
|
||||
5. **Monitoring**: Set up CloudWatch alarms for bucket access
|
||||
6. **Lifecycle Policies**: Configure S3 lifecycle policies for old versions
|
||||
7. **Resource Groups**: Use the created resource group for cost tracking
|
||||
8. **Documentation**: Document backend configuration for team members
|
||||
|
||||
## Example: Complete Setup
|
||||
|
||||
```hcl
|
||||
# Step 1: Create backend infrastructure
|
||||
module "backend" {
|
||||
source = "git@github.com:webuildyourcloud/terraform-aws-s3-backend.git"
|
||||
|
||||
namespace = "myapp-prod"
|
||||
force_destroy_state = false
|
||||
|
||||
principle_arns = [
|
||||
"arn:aws:iam::123456789012:role/TerraformRole"
|
||||
]
|
||||
}
|
||||
|
||||
# Step 2: Output configuration for easy reference
|
||||
output "backend_bucket" {
|
||||
value = module.backend.config.bucket
|
||||
description = "S3 bucket name for Terraform state"
|
||||
}
|
||||
|
||||
output "backend_dynamodb_table" {
|
||||
value = module.backend.config.dynamodb_table
|
||||
description = "DynamoDB table name for state locking"
|
||||
}
|
||||
|
||||
output "backend_role_arn" {
|
||||
value = module.backend.config.role_arn
|
||||
description = "IAM role ARN for backend access"
|
||||
}
|
||||
|
||||
output "backend_region" {
|
||||
value = module.backend.config.region
|
||||
description = "AWS region for backend resources"
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Cannot access state file
|
||||
- Verify IAM role has correct permissions
|
||||
- Check if `role_arn` is correctly specified in backend configuration
|
||||
- Ensure principal is allowed in `principle_arns`
|
||||
|
||||
### State locking errors
|
||||
- Verify DynamoDB table exists
|
||||
- Check for orphaned locks in DynamoDB
|
||||
- Ensure sufficient DynamoDB capacity (should not be an issue with PAY_PER_REQUEST)
|
||||
|
||||
### Backend initialization fails
|
||||
- Verify bucket and table names are correct
|
||||
- Check AWS credentials have appropriate permissions
|
||||
- Ensure region matches where resources were created
|
||||
|
||||
### Bucket name conflicts
|
||||
- The module uses random suffixes to prevent conflicts
|
||||
- If conflicts occur, destroy and recreate with a new namespace
|
||||
|
||||
## State File Organization
|
||||
|
||||
Recommended key structure:
|
||||
|
||||
```
|
||||
<environment>/<project>/<component>/terraform.tfstate
|
||||
|
||||
Examples:
|
||||
prod/networking/vpc/terraform.tfstate
|
||||
prod/compute/eks/terraform.tfstate
|
||||
prod/data/rds/terraform.tfstate
|
||||
staging/networking/vpc/terraform.tfstate
|
||||
dev/compute/eks/terraform.tfstate
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From Local State
|
||||
|
||||
```bash
|
||||
# 1. Create backend
|
||||
terraform apply -target=module.backend
|
||||
|
||||
# 2. Add backend configuration to your code
|
||||
# 3. Initialize with migration
|
||||
terraform init -migrate-state
|
||||
|
||||
# 4. Verify
|
||||
terraform state list
|
||||
```
|
||||
|
||||
### From Another S3 Backend
|
||||
|
||||
Update backend configuration and run:
|
||||
```bash
|
||||
terraform init -migrate-state -reconfigure
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This module is provided as-is for use within your organization.
|
||||
|
||||
2
examples/outputs.tf
Executable file
2
examples/outputs.tf
Executable file
@ -0,0 +1,2 @@
|
||||
output "s3backend" {
|
||||
value = module.s3backend.config
|
||||
3
examples/provider.tf
Executable file
3
examples/provider.tf
Executable file
@ -0,0 +1,3 @@
|
||||
provider "aws" {
|
||||
region = var.region
|
||||
}
|
||||
4
examples/s3backend.tf
Executable file
4
examples/s3backend.tf
Executable file
@ -0,0 +1,4 @@
|
||||
modules "s3backend" {
|
||||
source = "git::git@github.com:webuildyourcloud/terraform-aws-s3-backend.git?ref=tags/0.0.1"
|
||||
namespace = var.namespace
|
||||
}
|
||||
2
examples/terraform.tfvars
Executable file
2
examples/terraform.tfvars
Executable file
@ -0,0 +1,2 @@
|
||||
region = "eu-west-1"
|
||||
namspace = "example"
|
||||
0
examples/variables.tf
Executable file
0
examples/variables.tf
Executable file
0
outputs.tf
Normal file → Executable file
0
outputs.tf
Normal file → Executable file
0
variables.tf
Normal file → Executable file
0
variables.tf
Normal file → Executable file
0
versions.tf
Normal file → Executable file
0
versions.tf
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user