Migrate certificate-automation from consul-template to vault-agent
- Migrated Ansible integration from consul_template to vault_agent - Copied vault_agent role from terraform-vsphere-infra module - Created vault_agent-playbook.yml for deployment - Archived consul_template role as consul_template-legacy - Updated Terraform configuration: - Changed Ansible inventory group from consul_template to vault_agent - Added vault_secret_path variable for vault-agent - Added ssl_certs_dir and ssl_private_dir variables - Formatted all Terraform files - Implemented CI/CD pipeline: - Created .gitea/workflows/pipeline.yaml - Added TFLint, Tfsec, and Checkov security scans - Added Terraform validate step - Added SonarQube integration - Created sonar-project.properties - Documentation updates: - Updated README.md with vault-agent information - Added migration section comparing consul-template vs vault-agent - Updated CLAUDE.md with vault-agent architecture - Added vault-agent configuration examples Why vault-agent over consul-template: - Full AppRole support with role_id/secret_id files - Advanced token auto-renewal with auto_auth - Better credential security (separate files vs config) - Actively developed by HashiCorp Note: The ansible/ directory changes (vault_agent role and playbook) are not committed as the directory is in .gitignore. These files exist locally and will be deployed during Ansible runs.
This commit is contained in:
parent
47aaaa2143
commit
9c0d389dd3
116
.gitea/workflows/pipeline.yaml
Normal file
116
.gitea/workflows/pipeline.yaml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
name: Code Quality & Security Scan
|
||||||
|
jobs:
|
||||||
|
tflint:
|
||||||
|
name: TFLint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup TFLint
|
||||||
|
uses: terraform-linters/setup-tflint@v4
|
||||||
|
with:
|
||||||
|
tflint_version: latest
|
||||||
|
|
||||||
|
- name: Initialize TFLint
|
||||||
|
working-directory: terraform
|
||||||
|
run: tflint --init
|
||||||
|
|
||||||
|
- name: Run TFLint
|
||||||
|
working-directory: terraform
|
||||||
|
run: tflint --format compact
|
||||||
|
|
||||||
|
tfsec:
|
||||||
|
name: Tfsec Security Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: tflint
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run Tfsec
|
||||||
|
uses: aquasecurity/tfsec-action@v1.0.3
|
||||||
|
with:
|
||||||
|
working_directory: terraform
|
||||||
|
format: default
|
||||||
|
soft_fail: false
|
||||||
|
|
||||||
|
checkov:
|
||||||
|
name: Checkov Security Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: tfsec
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run Checkov
|
||||||
|
uses: bridgecrewio/checkov-action@v12
|
||||||
|
with:
|
||||||
|
directory: terraform
|
||||||
|
framework: terraform
|
||||||
|
output_format: cli
|
||||||
|
soft_fail: false
|
||||||
|
|
||||||
|
terraform-validate:
|
||||||
|
name: Terraform Validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: checkov
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: latest
|
||||||
|
|
||||||
|
- name: Terraform Format Check
|
||||||
|
working-directory: terraform
|
||||||
|
run: terraform fmt -check -recursive
|
||||||
|
|
||||||
|
- name: Terraform Init (for validation)
|
||||||
|
working-directory: terraform
|
||||||
|
env:
|
||||||
|
TF_VAR_vault_address: "https://vault.example.com:8200"
|
||||||
|
TF_VAR_environment: "test"
|
||||||
|
TF_VAR_short_hostname: "test-host"
|
||||||
|
run: terraform init -backend=false
|
||||||
|
|
||||||
|
- name: Terraform Validate
|
||||||
|
working-directory: terraform
|
||||||
|
env:
|
||||||
|
TF_VAR_vault_address: "https://vault.example.com:8200"
|
||||||
|
TF_VAR_environment: "test"
|
||||||
|
TF_VAR_short_hostname: "test-host"
|
||||||
|
run: terraform validate
|
||||||
|
|
||||||
|
sonarqube:
|
||||||
|
name: SonarQube Trigger
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: terraform-validate
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# Disabling shallow clone is recommended for improving relevancy of reporting
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: SonarQube Scan
|
||||||
|
uses: sonarsource/sonarqube-scan-action@v6
|
||||||
|
env:
|
||||||
|
SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
|
||||||
114
CLAUDE.md
Normal file
114
CLAUDE.md
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Repository Overview
|
||||||
|
|
||||||
|
This is a Terraform module for automated TLS certificate deployment using Vault, vault-agent, Terraform, and Ansible. The module creates Vault AppRole authentication and policies, then deploys vault-agent via Ansible to automatically fetch and deploy certificates from Vault.
|
||||||
|
|
||||||
|
**Note**: This module has been migrated from consul-template to vault-agent for better AppRole support and improved security.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Terraform Configuration (`terraform/`)
|
||||||
|
- **main.tf**: Creates Vault policies, AppRole authentication, and Ansible inventory
|
||||||
|
- **variables.tf**: Defines `environment` and `short_hostname` variables
|
||||||
|
- **outputs.tf**: Outputs sensitive AppRole credentials (role_id and secret_id)
|
||||||
|
- **backend.tf, provider.tf, data.tf**: Standard Terraform configuration files
|
||||||
|
|
||||||
|
### Ansible Configuration (`ansible/`)
|
||||||
|
- **vault_agent-playbook.yml**: Main playbook that deploys vault-agent
|
||||||
|
- **roles/vault_agent/**: Ansible role for vault-agent installation and configuration
|
||||||
|
- Downloads and installs vault binary from HashiCorp releases
|
||||||
|
- Creates systemd service for vault-agent
|
||||||
|
- Configures AppRole authentication with role_id/secret_id files
|
||||||
|
- Deploys certificate templates for automatic renewal
|
||||||
|
- **roles/consul_template-legacy/**: Archived legacy consul-template role (for reference)
|
||||||
|
- **collections/**: Contains Ansible collections (cloud.terraform, community.crypto, etc.)
|
||||||
|
|
||||||
|
### Key Components
|
||||||
|
- **Vault Integration**: Uses AppRole authentication for secure certificate access
|
||||||
|
- **Certificate Templates**: Automatically fetches certificates, private keys, and certificate chains
|
||||||
|
- **System Integration**: Configures systemd service and file permissions for certificate deployment
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
### Terraform Operations
|
||||||
|
```bash
|
||||||
|
cd terraform/
|
||||||
|
terraform init
|
||||||
|
terraform plan
|
||||||
|
terraform apply
|
||||||
|
terraform destroy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ansible Operations
|
||||||
|
```bash
|
||||||
|
cd ansible/
|
||||||
|
ansible-playbook -i inventory.yml vault_agent-playbook.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Certificate Template Files
|
||||||
|
- `certificate.tpl`: Certificate template (fullchain)
|
||||||
|
- `private_key.tpl`: Private key template
|
||||||
|
- `chain_pem.tpl`: Certificate chain template
|
||||||
|
|
||||||
|
**Note**: Template files are dynamically generated by the vault_agent role during deployment.
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- AppRole credentials are marked as sensitive in Terraform outputs
|
||||||
|
- Certificate files are deployed with restricted permissions (600)
|
||||||
|
- Vault policies follow principle of least privilege (read-only access to specific secret paths)
|
||||||
|
- Ansible Vault should be used for encrypting sensitive variables (`vault_credentials.yml`)
|
||||||
|
|
||||||
|
## Module Usage Pattern
|
||||||
|
|
||||||
|
1. Deploy Vault AppRoles and policies with Terraform
|
||||||
|
2. Generate Ansible Vault credentials using `ansible_vault_output.sh`
|
||||||
|
3. Run Ansible playbook to deploy vault-agent: `ansible-playbook vault_agent-playbook.yml`
|
||||||
|
4. vault-agent automatically fetches and renews certificates from Vault using AppRole authentication
|
||||||
|
|
||||||
|
## Why Vault-Agent?
|
||||||
|
|
||||||
|
This module migrated from consul-template to vault-agent for several reasons:
|
||||||
|
|
||||||
|
| Feature | consul-template | vault-agent |
|
||||||
|
|---------|----------------|-------------|
|
||||||
|
| AppRole Authentication | ❌ Limited support | ✅ Full support with role_id/secret_id files |
|
||||||
|
| Token Auto-Renewal | ⚠️ Basic | ✅ Advanced with auto_auth |
|
||||||
|
| Credential Storage | ❌ In config file | ✅ Separate secure files |
|
||||||
|
| Active Development | ⚠️ Maintenance mode | ✅ Actively developed |
|
||||||
|
|
||||||
|
## vault-agent Configuration
|
||||||
|
|
||||||
|
vault-agent uses AppRole auto_auth:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
auto_auth {
|
||||||
|
method "approle" {
|
||||||
|
mount_path = "auth/approle"
|
||||||
|
config = {
|
||||||
|
role_id_file_path = "/etc/vault-agent/role_id"
|
||||||
|
secret_id_file_path = "/etc/vault-agent/secret_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sink "file" {
|
||||||
|
config = {
|
||||||
|
path = "/opt/vault-agent/vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Certificate templates automatically fetch secrets from Vault:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
template {
|
||||||
|
source = "/etc/vault-agent/certificate.tpl"
|
||||||
|
destination = "/etc/ssl/certs/hostname.crt"
|
||||||
|
perms = 0644
|
||||||
|
command = "systemctl reload nginx" # Service-specific reload
|
||||||
|
}
|
||||||
|
```
|
||||||
36
README.md
36
README.md
@ -4,12 +4,12 @@ This Terraform module automates TLS certificate deployment by creating Vault App
|
|||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This module sets up the infrastructure needed to automatically fetch and deploy TLS certificates from HashiCorp Vault to target servers. It creates:
|
This module sets up the infrastructure needed to automatically fetch and deploy TLS certificates from HashiCorp Vault to target servers using Vault Agent. It creates:
|
||||||
|
|
||||||
- Vault policies with read-only access to certificate secrets
|
- Vault policies with read-only access to certificate secrets
|
||||||
- AppRole authentication backend configuration
|
- AppRole authentication backend configuration
|
||||||
- AppRole credentials for secure authentication
|
- AppRole credentials for secure authentication
|
||||||
- Ansible inventory entries for automated deployment
|
- Ansible inventory entries for automated vault-agent deployment
|
||||||
|
|
||||||
## What It Does
|
## What It Does
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ This module creates the following Vault resources:
|
|||||||
- Token Max TTL: 4 hours
|
- Token Max TTL: 4 hours
|
||||||
- Secret ID TTL: 24 hours
|
- Secret ID TTL: 24 hours
|
||||||
|
|
||||||
- **Ansible Host**: Added to `consul_template` group with Vault credentials
|
- **Ansible Host**: Added to `vault_agent` group with Vault credentials
|
||||||
|
|
||||||
## Secret Path Convention
|
## Secret Path Convention
|
||||||
|
|
||||||
@ -106,22 +106,25 @@ Example: `secret/data/production/web01/certificate`
|
|||||||
This module automatically creates an Ansible inventory entry with:
|
This module automatically creates an Ansible inventory entry with:
|
||||||
|
|
||||||
- Inventory hostname: `{short_hostname}`
|
- Inventory hostname: `{short_hostname}`
|
||||||
- Group: `consul_template`
|
- Group: `vault_agent`
|
||||||
- Variables:
|
- Variables:
|
||||||
- `vault_approle_role_id`
|
- `vault_approle_role_id`
|
||||||
- `vault_approle_secret_id`
|
- `vault_approle_secret_id`
|
||||||
- `vault_address`
|
- `vault_address`
|
||||||
|
- `vault_secret_path`
|
||||||
- `environment`
|
- `environment`
|
||||||
- `short_hostname`
|
- `short_hostname`
|
||||||
|
- `ssl_certs_dir`
|
||||||
|
- `ssl_private_dir`
|
||||||
|
|
||||||
The generated inventory can be used with the included Ansible playbooks in the `ansible/` directory to deploy consul-template for automated certificate retrieval.
|
The generated inventory can be used with the included Ansible playbooks in the `ansible/` directory to deploy vault-agent for automated certificate retrieval.
|
||||||
|
|
||||||
## Deployment Steps
|
## Deployment Steps
|
||||||
|
|
||||||
1. Deploy Vault AppRoles and policies with Terraform
|
1. Deploy Vault AppRoles and policies with Terraform
|
||||||
2. Generate Ansible Vault credentials (`ansible_vault_output.sh`)
|
2. Generate Ansible Vault credentials (`ansible_vault_output.sh`)
|
||||||
3. Run Ansible playbook to deploy consul-template
|
3. Run Ansible playbook to deploy vault-agent: `ansible-playbook vault_agent-playbook.yml`
|
||||||
4. consul-template automatically fetches and renews certificates from Vault
|
4. vault-agent automatically fetches and renews certificates from Vault using AppRole authentication
|
||||||
|
|
||||||
## Security Considerations
|
## Security Considerations
|
||||||
|
|
||||||
@ -135,9 +138,22 @@ The generated inventory can be used with the included Ansible playbooks in the `
|
|||||||
|
|
||||||
This module works in conjunction with:
|
This module works in conjunction with:
|
||||||
|
|
||||||
- **Ansible Playbooks** (in `ansible/` directory): Deploy consul-template to target servers
|
- **Ansible Playbooks** (in `ansible/` directory): Deploy vault-agent to target servers
|
||||||
- **Consul-Template**: Automatically fetches and renews certificates from Vault
|
- **Vault Agent**: Automatically fetches and renews certificates from Vault using AppRole authentication
|
||||||
- **Vault PKI**: Stores certificates that this module provides access to
|
- **Vault KV Secrets Engine**: Stores certificates that this module provides access to
|
||||||
|
|
||||||
|
## Migration from consul-template
|
||||||
|
|
||||||
|
This module has been migrated from consul-template to vault-agent for better AppRole support and improved security. Key differences:
|
||||||
|
|
||||||
|
| Feature | consul-template (legacy) | vault-agent (current) |
|
||||||
|
|---------|-------------------------|----------------------|
|
||||||
|
| AppRole Auth | ❌ Limited support | ✅ Full support with role_id/secret_id files |
|
||||||
|
| Token Management | ⚠️ Basic | ✅ Advanced auto_auth |
|
||||||
|
| Security | ❌ Credentials in config | ✅ Separate credential files |
|
||||||
|
| Active Development | ⚠️ Maintenance mode | ✅ Actively developed |
|
||||||
|
|
||||||
|
The legacy consul-template role is archived as `consul_template-legacy` for reference.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
13
sonar-project.properties
Normal file
13
sonar-project.properties
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
sonar.projectKey=terraform-certificate-automation
|
||||||
|
sonar.projectName=Terraform Certificate Automation Module
|
||||||
|
sonar.projectVersion=1.0
|
||||||
|
|
||||||
|
# Path to source directories
|
||||||
|
sonar.sources=terraform,ansible
|
||||||
|
|
||||||
|
# Exclusions
|
||||||
|
sonar.exclusions=**/*.tfvars,**/.terraform/**,**/files/**,**/collections/**,**/consul_template-legacy/**
|
||||||
|
|
||||||
|
# Terraform-specific settings
|
||||||
|
sonar.language=terraform
|
||||||
|
sonar.sourceEncoding=UTF-8
|
||||||
@ -1,11 +1,11 @@
|
|||||||
terraform {
|
terraform {
|
||||||
backend "s3" {
|
backend "s3" {
|
||||||
endpoints = {
|
endpoints = {
|
||||||
s3 = "https://minio.bsdserver.nl:443"
|
s3 = "https://minio.bsdserver.nl:443"
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket = "home-terraform"
|
bucket = "home-terraform"
|
||||||
key = "home/security/encryption/certificate-automation.tfstate"
|
key = "home/security/encryption/certificate-automation.tfstate"
|
||||||
|
|
||||||
# Configure credentials via environment variables:
|
# Configure credentials via environment variables:
|
||||||
# export AWS_ACCESS_KEY_ID="your-access-key"
|
# export AWS_ACCESS_KEY_ID="your-access-key"
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
locals {
|
locals {
|
||||||
secret_path = "secret/data/${var.environment}/${var.short_hostname}/certificate"
|
secret_path = "secret/data/${var.environment}/${var.short_hostname}/certificate"
|
||||||
policy_name = "${var.environment}-${var.short_hostname}-cert-policy"
|
policy_name = "${var.environment}-${var.short_hostname}-cert-policy"
|
||||||
approle_name = "${var.environment}-${var.short_hostname}-approle"
|
approle_name = "${var.environment}-${var.short_hostname}-approle"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "vault_policy" "cert_access" {
|
resource "vault_policy" "cert_access" {
|
||||||
name = local.policy_name
|
name = local.policy_name
|
||||||
policy = <<EOT
|
policy = <<EOT
|
||||||
path "${local.secret_path}" {
|
path "${local.secret_path}" {
|
||||||
capabilities = ["read"]
|
capabilities = ["read"]
|
||||||
@ -27,9 +27,9 @@ resource "vault_approle_auth_backend_role_secret_id" "cert_role_secret" {
|
|||||||
role_name = vault_approle_auth_backend_role.cert_role.role_name
|
role_name = vault_approle_auth_backend_role.cert_role.role_name
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "ansible_host" "consul_template_node" {
|
resource "ansible_host" "vault_agent_node" {
|
||||||
inventory_hostname = var.short_hostname
|
inventory_hostname = var.short_hostname
|
||||||
groups = ["consul_template"]
|
groups = ["vault_agent"]
|
||||||
|
|
||||||
vars = {
|
vars = {
|
||||||
ansible_user = "ansible"
|
ansible_user = "ansible"
|
||||||
@ -38,7 +38,10 @@ resource "ansible_host" "consul_template_node" {
|
|||||||
vault_approle_role_id = vault_approle_auth_backend_role.cert_role.role_id
|
vault_approle_role_id = vault_approle_auth_backend_role.cert_role.role_id
|
||||||
vault_approle_secret_id = vault_approle_auth_backend_role_secret_id.cert_role_secret.secret_id
|
vault_approle_secret_id = vault_approle_auth_backend_role_secret_id.cert_role_secret.secret_id
|
||||||
vault_address = var.vault_address
|
vault_address = var.vault_address
|
||||||
|
vault_secret_path = local.secret_path
|
||||||
environment = var.environment
|
environment = var.environment
|
||||||
short_hostname = var.short_hostname
|
short_hostname = var.short_hostname
|
||||||
|
ssl_certs_dir = "/etc/ssl/certs"
|
||||||
|
ssl_private_dir = "/etc/ssl/private"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,14 +11,14 @@ terraform {
|
|||||||
|
|
||||||
# Configure the Vault provider
|
# Configure the Vault provider
|
||||||
provider "vault" {
|
provider "vault" {
|
||||||
address = var.vault_address
|
address = var.vault_address
|
||||||
auth_login {
|
auth_login {
|
||||||
path = "auth/approle/login"
|
path = "auth/approle/login"
|
||||||
parameters = {
|
parameters = {
|
||||||
role_id = var.role_id
|
role_id = var.role_id
|
||||||
secret_id = var.secret_id
|
secret_id = var.secret_id
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ansible Provider
|
# Ansible Provider
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user