Patrick de Ruiter 16bb56c454
Some checks failed
Code Quality & Security Scan / TFLint (push) Successful in 26s
Code Quality & Security Scan / Terraform Destroy (push) Has been skipped
Code Quality & Security Scan / Tfsec Security Scan (push) Successful in 33s
Code Quality & Security Scan / Checkov Security Scan (push) Successful in 39s
Code Quality & Security Scan / Terraform Validate (push) Failing after 32s
Code Quality & Security Scan / SonarQube Scan (push) Has been skipped
Code Quality & Security Scan / Terraform Plan (push) Has been skipped
Code Quality & Security Scan / Terraform Apply (push) Has been skipped
feat: Add regex managers for Docker container versioning in Terraform
Add support for Renovate to detect and update Docker image versions
defined in Terraform files using annotation comments.

Changes:
- Add 3 regex managers to config.js.tpl for different annotation patterns:
  - Basic: # renovate: datasource=docker
  - With versioning: # renovate: datasource=docker versioning=semver
  - Separate variable: # renovate: datasource=docker depName=redis
- Update README.md with comprehensive Docker container annotation docs
- Update QUICKSTART.md with Terraform Docker container examples
- Add example-annotated-containers.tf with usage patterns

This enables Renovate to automatically create PRs when Docker images
used in Terraform container definitions have updates available.
2025-11-28 04:09:14 +01:00

25 KiB

Terraform Docker Renovate Module

Purpose

This Terraform module deploys a Renovate bot as a Docker container with the following features:

  • Renovate Container: Automatically updates dependencies in your repositories
  • Gitea Integration: Native support for Gitea platform with proper authentication
  • Traefik Integration: Automatically configures Traefik reverse proxy (optional)
  • DNS Management: Creates DNS CNAME records for the Renovate instance (optional)
  • Persistent Storage: Manages Docker volumes for configuration and cache
  • Vault Integration: Securely retrieves DNS credentials from HashiCorp Vault
  • Remote State Backend: Stores Terraform state in MinIO (S3-compatible storage)
  • Resource Limits: Configurable memory limits for container isolation

What It Does

The module creates and manages the following resources:

  1. Docker Volumes:

    • renovate-config: Persistent storage for configuration files
    • renovate-cache: Cache storage for improved performance
  2. Renovate Container:

    • Runs Renovate bot process
    • Connects to Traefik network for reverse proxy access (optional)
    • Configured with resource limits (Memory)
    • Configured with flexible restart policy
    • Logs sent to Docker daemon (managed by Loki)
  3. DNS Record (Optional):

    • Creates a CNAME record pointing to the hosting server

What is Renovate?

Renovate is an automated dependency update tool that:

  • Monitors dependencies across multiple package managers and platforms
  • Creates pull requests with dependency updates automatically
  • Supports semantic versioning and custom update schedules
  • Works with Docker, Terraform, npm, pip, and many other ecosystems
  • Integrates with CI/CD pipelines for automated testing

Common Use Cases

  • Automated Docker image updates with semantic versioning
  • Terraform module and provider version updates
  • Application dependency management (npm, pip, composer, etc.)
  • Security vulnerability patching through automatic updates
  • Consistent dependency versions across multiple repositories

Prerequisites

Before using this module, ensure you have:

  1. Docker Host: A Docker daemon accessible via TCP (configured at 192.168.2.170:2376)
  2. Docker TLS Certificates: Client certificates in ~/.docker/ directory
  3. Traefik Network: A Docker network named traefik_network must exist
  4. Gitea Instance: Running Gitea instance with API access
  5. Renovate Bot User: Dedicated user account in Gitea with appropriate permissions
  6. Gitea Access Token: Personal Access Token with the following scopes:
    • repo: Read and Write
    • user: Read
    • issue: Read and Write (Gitea ≥ 1.20.0)
    • organization: Read (Gitea ≥ 1.20.0)
  7. HashiCorp Vault: Running instance with:
    • AppRole authentication enabled
    • DNS credentials stored at secret/dns
    • Renovate credentials stored at secret/renovate (see Vault Setup section)
    • Role ID and Secret ID for authentication
  8. MinIO/S3 Backend: For Terraform state storage
  9. DNS Server: Supporting dynamic updates (TSIG authentication) - optional

Gitea Bot Setup

1. Create Renovate Bot User

In your Gitea instance:

  1. Create a new user account (e.g., renovate-bot)
  2. Configure the user with:
    • Full name: "Renovate Bot"
    • Email: renovate-bot@example.com
  3. Add the bot user as a collaborator to repositories you want to manage

2. Generate Personal Access Token

  1. Log in as the Renovate bot user
  2. Go to Settings → Applications → Generate New Token
  3. Token name: "Renovate Token"
  4. Select scopes:
    • repo (Read and Write)
    • user (Read)
    • issue (Read and Write)
    • organization (Read)
  5. IMPORTANT: Copy the token immediately - you won't be able to see it again
  6. Save the token securely - you'll need it for Vault storage (next step)

3. Store Credentials in Vault

CRITICAL: All Renovate configuration must be stored in Vault at secret/renovate before deploying this module.

# Authenticate to Vault
export VAULT_ADDR="https://your-vault-server:8200"
vault login -method=approle role_id=YOUR_ROLE_ID secret_id=YOUR_SECRET_ID

# Store Renovate credentials in Vault
vault kv put secret/renovate \
  renovate_platform="gitea" \
  renovate_endpoint="https://gitea.example.com/api/v1/" \
  renovate_token="YOUR_GITEA_TOKEN_FROM_STEP_2" \
  renovate_git_author="Renovate Bot <renovate-bot@example.com>" \
  renovate_username="renovate-bot"

# Verify the secrets are stored correctly
vault kv get secret/renovate

Required Keys in secret/renovate:

  • renovate_platform - Must be "gitea"
  • renovate_endpoint - Your Gitea API endpoint (must end with /api/v1/)
  • renovate_token - The Personal Access Token from Step 2
  • renovate_git_author - Git commit author for Renovate PRs
  • renovate_username - The Gitea username of the bot account

Note: If you regenerate the Gitea token, you must update it in Vault:

vault kv patch secret/renovate renovate_token="NEW_TOKEN_HERE"

4. Configure Repository Access

For each repository you want Renovate to manage:

  1. Add renovate-bot as a collaborator with Write access
  2. Or use autodiscovery to automatically find all accessible repositories

How to Use

1. Basic Usage with Gitea

module "renovate" {
  source = "./terraform-docker-renovate"

  # Infrastructure
  domain    = "bsdserver.nl"
  role_id   = var.vault_role_id
  secret_id = var.vault_secret_id

  # Gitea Configuration
  renovate_platform  = "gitea"
  renovate_endpoint  = "https://gitea.example.com/api/v1/"
  renovate_token     = var.renovate_token  # Store securely in Vault or use env var
  renovate_git_author = "Renovate Bot <renovate-bot@example.com>"
  renovate_username  = "renovate-bot"
}

2. Custom Configuration

module "renovate" {
  source = "./terraform-docker-renovate"

  # Infrastructure
  domain    = "bsdserver.nl"
  role_id   = var.vault_role_id
  secret_id = var.vault_secret_id

  # Container configuration
  container_name   = "renovate"
  renovate_image   = "renovate/renovate:latest"
  restart_policy   = "unless-stopped"

  # Resource limits
  memory_limit      = 2048
  memory_swap_limit = -1

  # Gitea platform configuration
  renovate_platform     = "gitea"
  renovate_endpoint     = "https://gitea.bsdserver.nl/api/v1/"
  renovate_token        = var.renovate_token
  renovate_git_author   = "Renovate Bot <renovate-bot@bsdserver.nl>"
  renovate_username     = "renovate-bot"
  renovate_autodiscover = true

  # Optional GitHub.com token for changelogs
  github_com_token = var.github_token

  # Logging
  log_level = "info"

  # Additional environment variables
  extra_env_vars = [
    "RENOVATE_REQUIRE_CONFIG=optional"
  ]
}

3. Configure Backend (Optional)

If using remote state storage (recommended), configure the backend:

# Option 1: Using environment variables
export AWS_ACCESS_KEY_ID="your-minio-access-key"
export AWS_SECRET_ACCESS_KEY="your-minio-secret-key"

terraform init \
  -backend-config="endpoints={s3=\"https://minio.example.com:443\"}" \
  -backend-config="bucket=terraform-state" \
  -backend-config="key=docker/renovate/terraform.tfstate" \
  -backend-config="region=main" \
  -backend-config="skip_credentials_validation=true" \
  -backend-config="skip_metadata_api_check=true" \
  -backend-config="skip_requesting_account_id=true" \
  -backend-config="skip_region_validation=true" \
  -backend-config="use_path_style=true"

Or create a backend.hcl file:

# backend.hcl
endpoints = {
  s3 = "https://minio.example.com:443"
}
bucket                      = "terraform-state"
key                         = "docker/renovate/terraform.tfstate"
region                      = "main"
skip_credentials_validation = true
skip_metadata_api_check     = true
skip_requesting_account_id  = true
skip_region_validation      = true
use_path_style              = true

Then initialize:

export AWS_ACCESS_KEY_ID="your-minio-access-key"
export AWS_SECRET_ACCESS_KEY="your-minio-secret-key"
terraform init -backend-config=backend.hcl

4. Initialize Terraform

# For local state (not recommended for production)
terraform init

# Or with remote backend (see step 3)
terraform init -backend-config=backend.hcl

This will:

  • Download required providers (Docker, Vault, DNS)
  • Configure the backend for state storage (if specified)

5. Plan Deployment

terraform plan

Review the planned changes to ensure everything is correct.

6. Apply Configuration

terraform apply

Confirm the changes to deploy the Renovate bot.

7. Verify Deployment

After deployment:

  1. Check Container Status:

    docker ps | grep renovate
    
  2. View Container Logs:

    docker logs renovate -f
    
  3. Verify Configuration:

    docker exec renovate cat /usr/src/app/config.js
    

Repository Configuration

Adding Renovate to a Repository

To enable Renovate in a repository, create a renovate.json file in the repository root:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended"
  ],
  "assignees": ["@yourusername"],
  "labels": ["renovate"],
  "dependencyDashboard": true,
  "packageRules": [
    {
      "description": "Automerge minor and patch updates",
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true
    }
  ],
  "docker": {
    "enabled": true,
    "pinDigests": false
  },
  "terraform": {
    "enabled": true
  }
}

An example configuration is provided in files/example-renovate.json.

Docker-Compose Repository Example

For repositories with docker-compose.yml files:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "docker-compose": {
    "enabled": true
  },
  "packageRules": [
    {
      "matchDatasources": ["docker"],
      "matchUpdateTypes": ["major"],
      "enabled": false
    }
  ]
}

Terraform Repository Example

For repositories with Terraform code:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "terraform": {
    "enabled": true
  },
  "packageRules": [
    {
      "matchDatasources": ["terraform-provider", "terraform-module"],
      "automerge": false,
      "schedule": ["before 6am on Monday"]
    }
  ]
}

Docker Container Versioning in Terraform

This Renovate deployment includes regex managers that can detect and update Docker image versions defined in Terraform files. This is useful when you deploy Docker containers via Terraform and want Renovate to keep those images up to date.

How It Works

Add a special comment annotation above your image definition in your Terraform code. Renovate will then detect the Docker image and create PRs when updates are available.

Annotation Format

Basic annotation (combined image:tag format):

locals {
  containers = {
    redis = {
      # renovate: datasource=docker
      image = "docker.io/library/redis:8"
      # ... other settings
    }

    traefik = {
      # renovate: datasource=docker
      image = "traefik:3.1.2"
      ports = [80, 443]
    }

    grafana = {
      # renovate: datasource=docker
      image = "grafana/grafana:11.2.0"
      # ... other settings
    }
  }
}

With explicit versioning scheme (for non-standard versioning):

vault = {
  # renovate: datasource=docker versioning=semver
  image = "hashicorp/vault:1.17.3"
}

minio = {
  # renovate: datasource=docker versioning=regex
  image = "minio/minio:RELEASE.2024-08-29T01-40-52Z"
}

Separate version variable:

# renovate: datasource=docker depName=redis
variable "redis_version" {
  type    = string
  default = "8.0.0"
}

Supported Patterns

Pattern Example Use Case
Combined image:tag image = "nginx:1.25.0" Most common - image and version in one string
With registry prefix image = "docker.io/library/redis:8" Official images with full path
Custom versioning versioning=semver Images with non-standard version formats
Separate variable depName=redis + version = "8.0.0" When image and version are split

Example: Complete Container Definition

# Paperless-NGX with Redis broker
locals {
  services = {
    paperless-broker = {
      # renovate: datasource=docker
      image = "docker.io/library/redis:8"

      healthcheck = {
        test         = ["CMD", "redis-cli", "ping"]
        interval     = "30s"
        timeout      = "5s"
        retries      = 3
      }

      volumes = {
        "paperless-redisdata" = "/data"
      }

      networks        = ["paperless-backend-network"]
      container_ports = ["6379"]
    }

    paperless-webserver = {
      # renovate: datasource=docker
      image = "ghcr.io/paperless-ngx/paperless-ngx:2.12.1"

      networks        = ["paperless-backend-network", "traefik_network"]
      use_traefik     = true
      container_ports = ["8000"]
    }
  }
}

When Renovate scans this repository, it will:

  1. Detect redis:8 and create PRs for Redis updates
  2. Detect paperless-ngx:2.12.1 and create PRs for Paperless-NGX updates
  3. Continue to update Terraform providers and modules as usual

An example annotated container file is provided in files/example-annotated-containers.tf.

Variables

Terraform Variables

These variables are defined in variables.tf and can be set via terraform.tfvars or environment variables:

Variable Description Type Default Required
container_name Name of the Renovate container string "renovate" No
renovate_image Docker image for Renovate string "renovate/renovate:latest" No
restart_policy Restart policy for the container string "unless-stopped" No
memory_limit Memory limit for the container in MB number 2048 No
memory_swap_limit Memory swap limit in MB (-1 for unlimited) number -1 No
domain Domain name for the application string "bsdserver.lan" No
dns_name DNS name for the Renovate service string null (uses container_name) No
create_cname_record Whether to create a DNS CNAME record bool false No
dns_servers List of DNS servers for hostname resolution list(string) [] (uses Docker default) No
renovate_autodiscover Enable autodiscovery of repositories bool true No
renovate_onboarding_config Onboarding configuration for Renovate (JSON string) string See variables.tf No
github_com_token GitHub.com token for fetching changelogs string "" No
log_level Log level for Renovate (debug, info, warn, error) string "debug" No
extra_env_vars Additional environment variables for the container list(string) [] No
upload_config_file Upload a config.js file to the container bool true No
role_id Vault AppRole Role ID for authentication string - Yes
secret_id Vault AppRole Secret ID for authentication string - Yes
vault_skip_tls_verify Skip TLS verification for Vault (self-signed certs) bool true No

Vault-Stored Configuration

These values are NOT Terraform variables. They must be stored in HashiCorp Vault at path secret/renovate:

Vault Key Description Required
renovate_platform Git platform (must be "gitea") Yes
renovate_endpoint Gitea API endpoint (e.g., https://git.example.com/api/v1/) Yes
renovate_token Gitea Personal Access Token for the bot user Yes
renovate_git_author Git commit author (e.g., "Renovate Bot <bot@example.com>") Yes
renovate_username Gitea username of the bot account (e.g., "renovate-bot") Yes

See the "Store Credentials in Vault" section in Gitea Bot Setup for complete instructions on storing these values.

Outputs

Output Description
container_id ID of the Renovate container
container_name Name of the Renovate container
config_volume Name of the config volume
cache_volume Name of the cache volume
renovate_platform Platform configured for Renovate
renovate_endpoint API endpoint configured for Renovate

Configuration Details

Hardcoded Values

The following values are hardcoded in provider.tf and may need customization:

  • Docker Host: tcp://192.168.2.170:2376 (provider.tf:26)
  • Vault Address: https://wbyc-srv-docker01.bsdserver.lan:8200 (provider.tf:33)

Note: Backend configuration (MinIO/S3) is no longer hardcoded. Configure it via:

  • Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  • Command-line flags during terraform init (see "Configure Backend" section)
  • Backend configuration file (backend.hcl)

Security Considerations

Security Improvements:

  1. No Privileged Mode: Container runs without elevated privileges
  2. No Root User: Runs as standard user
  3. No Docker Socket: Docker socket is not mounted
  4. Resource Limits: Memory limits prevent resource exhaustion
  5. Token Security: Renovate token is marked as sensitive in Terraform
  6. Vault Integration: DNS credentials stored securely in Vault

⚠️ Security Notes:

  1. Backend Credentials: Use environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) instead of hardcoding
  2. Token Management: Store renovate_token in Vault or use environment variables
  3. Repository Access: Ensure bot user only has access to intended repositories
  4. Log Retention: Logs are sent to Docker daemon - ensure proper retention policies
  5. Network Security: Renovate connects to external APIs - ensure proper firewall rules

Providers

This module uses the following Terraform providers:

  • docker (kreuzwerker/docker v3.0.2): For Docker resource management
  • vault (hashicorp/vault v3.25.0): For secrets management
  • dns: For DNS record management with TSIG authentication

Managing Configuration

The module includes a config.js.tpl template that automatically configures Renovate based on your variables. Set upload_config_file = true to use this method.

Option 2: Manual Configuration

Mount a custom config.js file to the config volume:

# Create config.js
cat > config.js << 'EOF'
module.exports = {
  platform: 'gitea',
  endpoint: 'https://gitea.example.com/api/v1/',
  gitAuthor: 'Renovate Bot <renovate-bot@example.com>',
  username: 'renovate-bot',
  autodiscover: true,
  onboardingConfig: {
    $schema: 'https://docs.renovatebot.com/renovate-schema.json',
    extends: ['config:recommended'],
  },
};
EOF

# Copy to volume
docker run --rm -v renovate-config:/config -v $(pwd):/source alpine \
  cp /source/config.js /config/

# Restart container
docker restart renovate

Option 3: Environment Variables Only

Set upload_config_file = false and rely solely on environment variables configured in the module.

Scheduling Renovate Runs

Renovate can be scheduled using various methods:

Option 1: Cron Job

# Add to crontab to run daily at 2 AM
0 2 * * * docker restart renovate

Option 2: Gitea Actions/Workflows

Create .gitea/workflows/renovate.yaml in a dedicated repository:

name: Renovate
on:
  schedule:
    - cron: '0 2 * * *'
  workflow_dispatch:

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Renovate
        run: |
          docker restart renovate || true

Option 3: System Timer

Create a systemd timer for automated scheduling.

Troubleshooting

Container Won't Start

docker logs renovate

Check for:

  • Invalid Gitea endpoint or token
  • Network connectivity issues
  • Missing configuration
  • Resource limit issues

Renovate Not Creating PRs

Verify:

  1. Bot user has write access to repositories
  2. Gitea token has correct permissions
  3. Repositories have valid renovate.json configuration
  4. Check logs for API errors: docker logs renovate

Authentication Failures

  • Verify token scopes in Gitea settings
  • Ensure token hasn't expired
  • Check endpoint URL is correct (should end with /api/v1/)
  • Verify bot user account is active

DNS Record Not Created

  • Verify Vault DNS credentials are correct
  • Check DNS server allows dynamic updates
  • Ensure TSIG key has proper permissions

Rate Limiting Issues

If you see rate limit errors:

  1. Add github_com_token for GitHub.com changelog access
  2. Configure prConcurrentLimit in repository config
  3. Adjust scheduling to reduce API calls

Maintenance

Updating Renovate

# Pull latest image
docker pull renovate/renovate:latest

# Recreate container
terraform apply -replace=docker_container.renovate

Viewing Logs

# Container logs
docker logs renovate -f

# Filter for specific repository
docker logs renovate 2>&1 | grep "repository-name"

Backup

The Renovate data is stored in Docker volumes. To backup:

# Backup config
docker run --rm -v renovate-config:/data -v $(pwd):/backup alpine \
  tar czf /backup/renovate-config-backup.tar.gz /data

# Backup cache
docker run --rm -v renovate-cache:/data -v $(pwd):/backup alpine \
  tar czf /backup/renovate-cache-backup.tar.gz /data

Restore

# Restore config
docker run --rm -v renovate-config:/data -v $(pwd):/backup alpine \
  tar xzf /backup/renovate-config-backup.tar.gz -C /

# Restore cache
docker run --rm -v renovate-cache:/data -v $(pwd):/backup alpine \
  tar xzf /backup/renovate-cache-backup.tar.gz -C /

Advanced Configuration

Custom Renovate Image

To use a specific version:

module "renovate" {
  source = "./terraform-docker-renovate"

  renovate_image = "renovate/renovate:37.100.0"
  # ... other variables
}

Multiple Platform Support

While this module is optimized for Gitea, you can configure it for other platforms:

module "renovate_github" {
  source = "./terraform-docker-renovate"

  renovate_platform = "github"
  renovate_endpoint = "https://api.github.com/"
  renovate_token    = var.github_token
  # ... other variables
}

SonarQube Integration

Add SonarQube scanning to Renovate PRs by configuring your repository's renovate.json:

{
  "extends": ["config:recommended"],
  "postUpgradeTasks": {
    "commands": [
      "sonar-scanner -Dsonar.projectKey=myproject"
    ]
  }
}

Integration with CI/CD

Gitea Actions Integration

Renovate PRs can automatically trigger Gitea Actions workflows. Example .gitea/workflows/test.yaml:

name: Test Dependencies
on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Tests
        run: |
          docker-compose up -d
          docker-compose exec -T app npm test

Pipeline Configuration

For automated testing and deployment:

  1. Configure branch protection rules in Gitea
  2. Require status checks to pass before merging
  3. Enable auto-merge in renovate.json for passing PRs

Best Practices

  1. Start with Manual Approval: Don't enable automerge until you trust the process
  2. Use Dependency Dashboard: Enable "dependencyDashboard": true for visibility
  3. Schedule Updates: Use schedule to avoid overwhelming your team
  4. Group Updates: Group related dependencies to reduce PR noise
  5. Test Updates: Always have CI/CD tests run on Renovate PRs
  6. Monitor Logs: Regularly check Renovate logs for errors
  7. Pin Versions: Use semantic versioning tags instead of latest

Example Workflow

  1. Initial Setup:

    • Create Renovate bot user in Gitea
    • Generate access token with required scopes
    • Deploy this Terraform module
    • Add bot as collaborator to repositories
  2. Repository Configuration:

    • Add renovate.json to repository root
    • Configure package rules and schedules
    • Enable dependency dashboard
  3. First Run:

    • Renovate creates onboarding PR
    • Review and merge onboarding PR
    • Renovate starts scanning dependencies
  4. Ongoing:

    • Renovate creates PRs for updates
    • CI/CD tests run automatically
    • Review and merge PRs
    • Monitor dependency dashboard

Resources

License

This module is part of the webuildyourcloud automation infrastructure.

Contributing

When contributing, ensure:

  • Terraform code follows best practices
  • Variables are properly documented
  • Security implications are considered
  • State backend configuration is tested
  • Configuration examples are validated