Skip to content

This repo implements tailscale's pgproxy on top of chainguard's Golang container image using multi-stage building, providing a minimal attack surface. Pgproxy.go was designed by tailscale's team and recently open sourced for the community.

Notifications You must be signed in to change notification settings

rafitox/pgproxy_tailscale

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

12 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

pgproxy_tailscale

This repository provides a secure and minimal Docker image for Tailscale's pgproxy, built using Chainguard's hardened, distroless Golang base image with a multi-stage build process.

Tailscale's pgproxy.go was designed internally and recently open-sourced, enabling secure, identity-aware access to PostgreSQL instances over Tailscale mTLS. This implementation focuses on reducing the attack surface by using a minimal container image and following container hardening best practices.

πŸ—οΈ Deployment Options

This repository offers two deployment methods:

  1. 🐳 Docker Compose - Local development and testing
  2. ☁️ AWS Terraform - Production-ready cloud infrastructure

Choose the deployment method that best fits your needs:

  • Use Docker Compose for local development, testing, or simple deployments
  • Use AWS Terraform for production environments with auto-scaling, managed databases, and enterprise security features

🐳 Docker Compose Deployment

Perfect for local development and testing environments.

πŸ“‹ Prerequisites

For Docker Compose

  • Docker and Docker Compose installed
  • Tailscale account and access to admin panel
  • SSL/TLS certificates for PostgreSQL (including CA)

For AWS Terraform

  • AWS CLI configured with appropriate permissions
  • Terraform >= 1.0 installed
  • Tailscale account and API key

πŸš€ Step-by-Step Usage Guide

1. Certificate Preparation

Make sure you have the necessary certificates in the certificates/ directory:

certificates/
β”œβ”€β”€ ca.pem          # Certificate Authority certificate
β”œβ”€β”€ server.crt      # PostgreSQL server certificate
└── server.key      # PostgreSQL server private key

2. Environment Variables Configuration

Create a .env file in the project root with the following variables:

# PostgreSQL configuration
POSTGRES_USER=your_username
POSTGRES_PASSWORD=your_secure_password

# Tailscale API Key
TSKEY_API=tskey-api-xxxxxx-xxxxxxxxxxxxxxxxx

To obtain the TSKEY_API:

  1. Access the Tailscale admin panel
  2. Go to Settings β†’ Keys
  3. Generate a new Auth Key with appropriate permissions

3. Image Building (Optional)

If you want to build the image locally instead of using the pre-built image:

# Build the image
docker build -t pgproxy:local .

# Update docker-compose.yaml to use the local image
# Change: image: rafaelribeiro96/pgproxy:1.82.5
# To:     image: pgproxy:local

4. Stack Execution

Run the complete stack with Docker Compose:

# Start the services
docker-compose up -d

# Check if containers are running
docker-compose ps

# Check pgproxy logs
docker-compose logs -f pgproxy

# Check PostgreSQL logs
docker-compose logs -f postgres

5. Configuration Verification

After starting the services, verify everything is working:

# Check if pgproxy is listening on port 5432
netstat -tulpn | grep :5432

# Test local connection (if needed)
docker-compose exec postgres psql -U your_username -d test_db

6. Connection via Tailscale

Once pgproxy is running and connected to Tailscale:

  1. Connect your client to the same Tailnet
  2. Use the hostname pgproxy-node to connect to PostgreSQL
  3. The connection will be automatically authenticated via Tailscale mTLS

Connection example:

psql -h pgproxy-node -p 5432 -U your_username -d test_db

πŸ”§ Advanced Configuration

Hostname Customization

To change the Tailscale hostname, edit the docker-compose.yaml:

command:
  [
    "--hostname", "my-custom-pgproxy",
    # ... other parameters
  ]

Network Configuration

The project uses a custom bridge network (pgnet) for isolation. Containers communicate internally through this network.

Persistent Volumes

  • pgdata: PostgreSQL data
  • ./pgproxy-state: Tailscale authentication state

πŸ› οΈ Troubleshooting

Common Issues

  1. Certificate error: Verify that certificates are in the correct format and have adequate permissions
  2. Tailscale authentication failure: Check if TSKEY_API is valid and has necessary permissions
  3. Connection refused: Make sure both containers are on the same network

Useful Logs

# Detailed pgproxy logs
docker-compose logs --tail=100 -f pgproxy

# PostgreSQL logs
docker-compose logs --tail=100 -f postgres

# Container status
docker-compose ps

πŸ”’ Security Considerations

  • This setup uses runsc runtime (gVisor) for additional isolation
  • Certificates are mounted as read-only
  • PostgreSQL runs with non-root user (uid:gid 70:70)
  • Base images are hardened and distroless from Chainguard

☁️ AWS Terraform Deployment

For production environments with enterprise-grade security, auto-scaling, and managed services.

πŸ—οΈ Infrastructure Overview

The Terraform configuration deploys:

  • AWS Resource Group: Organizes all resources for easy management
  • Aurora Serverless v2: Auto-scaling PostgreSQL database (0.5-16 ACUs)
  • AWS Lambda: Function for pgproxy integration and health monitoring
  • VPC & Security Groups: Network isolation and security controls
  • AWS Secrets Manager: Secure storage for credentials and API keys
  • KMS Encryption: Encryption at rest for all secrets
  • CloudWatch: Comprehensive logging and monitoring

πŸš€ Quick Start - AWS Deployment

  1. Navigate to Terraform directory:

    cd terraform
  2. Configure variables:

    # Copy example configuration
    cp terraform.tfvars.example terraform.tfvars
    
    # Edit with your specific values
    nano terraform.tfvars
  3. Set sensitive variables:

    export TF_VAR_tailscale_auth_key="tskey-api-xxxxxx-xxxxxxxxxxxxxxxxx"
    export TF_VAR_database_password_override="your-secure-password"
  4. Deploy infrastructure:

    # Initialize Terraform
    terraform init
    
    # Review planned changes
    terraform plan
    
    # Deploy infrastructure
    terraform apply
  5. Verify deployment:

    # View all outputs
    terraform output
    
    # Test Lambda function
    aws lambda invoke \
      --function-name $(terraform output -raw lambda_function_name) \
      --payload '{"action": "health_check"}' \
      response.json && cat response.json

πŸ”§ AWS Configuration Options

VPC Configuration

Create new VPC (default):

create_vpc = true
vpc_cidr   = "10.0.0.0/16"

Use existing VPC:

create_vpc          = false
existing_vpc_id     = "vpc-xxxxxxxxx"
existing_subnet_ids = ["subnet-xxxxxxxxx", "subnet-yyyyyyyyy"]

Aurora Serverless Scaling

aurora_min_capacity = 0.5   # Minimum ACUs (scales to zero cost when idle)
aurora_max_capacity = 16    # Maximum ACUs for peak loads

Lambda Configuration

lambda_memory_size = 128    # Memory in MB
lambda_timeout     = 30     # Timeout in seconds

πŸ” AWS Security Features

  • Secrets Manager Integration: All credentials encrypted and managed
  • VPC Isolation: Database in private subnets only
  • Security Groups: Restrictive network access rules
  • KMS Encryption: Custom encryption keys for secrets
  • IAM Least Privilege: Minimal required permissions
  • Performance Insights: Database monitoring and optimization

πŸ’° Cost Optimization

  • Aurora Serverless v2: Automatically scales down to 0.5 ACU when idle
  • Lambda: Pay only for execution time
  • Configurable log retention: Control CloudWatch costs
  • Resource tagging: Track costs by environment/project

πŸ“Š Monitoring & Observability

  • CloudWatch Logs: Centralized logging for Lambda and Aurora
  • Performance Insights: Database performance monitoring
  • Custom metrics: Application-specific monitoring
  • Tagging strategy: Organized resource management

πŸ› οΈ AWS Troubleshooting

AWS Common Issues

  1. Lambda VPC timeout: Ensure NAT Gateway or VPC endpoints for AWS services
  2. Database connection errors: Verify security groups and subnet configuration
  3. Secrets access denied: Check IAM permissions for Lambda execution role
  4. Terraform state issues: Use remote state backend for team environments

Useful AWS Commands

# Check Aurora cluster status
aws rds describe-db-clusters \
  --db-cluster-identifier $(terraform output -raw aurora_cluster_id)

# View Lambda logs
aws logs tail /aws/lambda/$(terraform output -raw lambda_function_name) --follow

# Test database connectivity
aws lambda invoke \
  --function-name $(terraform output -raw lambda_function_name) \
  --payload '{"action": "database_test"}' \
  response.json && cat response.json

# Check resource costs
aws ce get-cost-and-usage \
  --time-period Start=2024-01-01,End=2024-01-31 \
  --granularity MONTHLY \
  --metrics BlendedCost

πŸ“ Terraform File Structure

terraform/
β”œβ”€β”€ main.tf                    # Main infrastructure configuration
β”œβ”€β”€ variables.tf               # Input variables and validation
β”œβ”€β”€ vault.tf                   # Secrets Manager and KMS configuration
β”œβ”€β”€ outputs.tf                 # Resource outputs and connection info
β”œβ”€β”€ terraform.tfvars.example   # Configuration template
β”œβ”€β”€ build_lambda.sh            # Lambda deployment package builder
β”œβ”€β”€ .gitignore                 # Terraform-specific ignore rules
β”œβ”€β”€ README.md                  # Detailed Terraform documentation
└── lambda/
    β”œβ”€β”€ lambda_function.py     # Lambda function implementation
    └── requirements.txt       # Python dependencies

πŸš€ Production Considerations

For production deployments, consider:

  1. Remote State Backend: Use S3 + DynamoDB for state management
  2. Multi-Environment: Separate workspaces for dev/staging/prod
  3. CI/CD Integration: Automate deployments with GitHub Actions/GitLab CI
  4. Backup Strategy: Enable automated backups and point-in-time recovery
  5. Monitoring Alerts: Set up CloudWatch alarms for critical metrics
  6. Security Scanning: Regular vulnerability scans and compliance checks


πŸ“š Additional Resources

Official Documentation

AWS Resources

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly (both Docker and Terraform deployments)
  5. Submit a pull request

πŸ“„ License

This project follows the same license as the original Tailscale pgproxy implementation.

πŸ†˜ Support

  • Docker Issues: Check container logs and Docker Compose configuration
  • AWS Issues: Review CloudWatch logs and AWS resource status
  • Terraform Issues: Verify configuration and check Terraform state
  • General Questions: Open an issue in this repository

About

This repo implements tailscale's pgproxy on top of chainguard's Golang container image using multi-stage building, providing a minimal attack surface. Pgproxy.go was designed by tailscale's team and recently open sourced for the community.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •