This project provides a complete, automated solution for deploying a production-ready HashiCorp Vault server and a Minio S3-compatible object storage server using Docker Compose. It then uses Terraform to provision a robust Public Key Infrastructure (PKI) hierarchy, including a Root CA and an Intermediate CA, enabling instant issuance of leaf certificates.
- Overview
- Architecture
- Features
- Prerequisites
- Getting Started
- Terraform PKI Provisioning
- Project Structure
The primary goal of this tool stack is to simplify and accelerate the setup of a secure and production-grade PKI system. By combining Docker for service deployment and Terraform for infrastructure as code, you can stand up a complete Vault environment and provision a two-tier CA hierarchy in minutes.
This setup is ideal for development, testing, or as a foundational building block for a production environment where you need to manage TLS certificates for internal services, Kubernetes, or other applications.
The architecture consists of two main parts:
-
Service Deployment (Docker Compose):
- HashiCorp Vault: The core of the PKI system. It runs in server mode with a file storage backend for persistence and is configured with TLS for secure communication.
- Minio: A high-performance, S3-compatible object storage server. While the default Vault configuration uses a file backend, Minio is included for easy integration as a more robust storage solution (e.g., for Vault's Raft backend or other data).
-
Infrastructure Provisioning (Terraform):
- PKI Root CA: A long-lived, self-signed Root Certificate Authority. This is the trust anchor of your PKI.
- PKI Intermediate CA: A shorter-lived Intermediate CA signed by the Root CA. All end-entity (leaf) certificates will be issued by this intermediate, protecting the root key.
- Kubernetes Auth: A module to configure Vault to authenticate requests from Kubernetes clusters, allowing pods to securely request certificates.
- Certificate Issuance: A module to request and issue leaf certificates for your applications and services.
graph TD
subgraph "Local Machine"
A[User] -- runs --> B(docker-compose up);
A -- runs --> C(terraform apply);
end
subgraph "Docker Environment"
B --> D{Vault Server};
B --> E{Minio Server};
end
subgraph "Vault PKI Engine"
F[Root CA] -->|signs| G[Intermediate CA];
G -->|issues| H[Leaf Certificate];
end
subgraph "Terraform Provisioning"
C -- provisions --> D;
C -- configures --> F;
C -- configures --> G;
C -- requests --> H;
end
style A fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
style E fill:#bbf,stroke:#333,stroke-width:2px
This project establishes a two-tier Certificate Authority (CA) hierarchy, which is a security best practice for Public Key Infrastructure (PKI). This structure enhances security by keeping the Root CA offline and protected, while using the Intermediate CA for the day-to-day operations of issuing and managing certificates.
The chain of trust is as follows:
-
Root CA:
- This is the trust anchor of the entire system.
- It is self-signed and has a very long validity period (e.g., 20 years).
- Its primary and only role is to sign the certificate for the Intermediate CA.
- In a production environment, the Root CA's private key should be kept highly secure and offline.
-
Intermediate CA:
- This CA is signed by the Root CA, establishing a chain of trust back to the root.
- It has a shorter validity period than the Root CA (e.g., 10 years).
- This is the CA that will issue end-entity certificates (leaf certificates) for your servers, applications, and users.
- If the Intermediate CA is ever compromised, it can be revoked by the Root CA without affecting the entire PKI.
-
Leaf Certificates:
- These are the certificates used by your services (e.g., for TLS on a web server).
- They are signed by the Intermediate CA and have a much shorter validity period (e.g., 30-90 days).
- Clients that trust the Root CA will automatically trust any certificate issued by the Intermediate CA.
This hierarchical model provides a balance of security and operational flexibility.
- Automated Deployment: Spin up Vault and Minio with a single
docker-composecommand. - Production-Ready Vault: Configured with TLS and persistent storage.
- Infrastructure as Code: The entire PKI setup is defined in Terraform, ensuring it is repeatable, versionable, and easy to manage.
- Two-Tier CA Hierarchy: Follows best practices by isolating the Root CA and issuing certificates from an Intermediate CA.
- Modular Terraform Code: The Terraform configuration is broken down into logical modules for clarity and reusability.
- Kubernetes Integration: Built-in support for configuring Vault's Kubernetes authentication method.
Before you begin, ensure you have the following installed:
- Docker: Install Docker
- Docker Compose: Install Docker Compose
- Terraform: Install Terraform
- OpenSSL: For generating TLS certificates.
Follow these steps to deploy the services and prepare for PKI provisioning.
git clone https://github.com/omidiyanto/vault-pki-internal-stack.git
cd vault-pki-internal-stackVault is configured to use TLS. The provided ssl.sh script will generate the necessary self-signed certificates.
bash ssl.shThis will create a tls directory containing tls.crt and tls.key.
Deploy the containers using Docker Compose:
docker-compose up -d- Vault UI will be available at
https://localhost:8200 - Minio Console will be available at
http://localhost:8791(MinIO Credentials:admin/v1Ua7xi0E70HzCbE)
Since this is a new Vault instance, you must initialize it to get the unseal keys and the initial root token.
-
Exec into the Vault container:
docker exec -it vault sh -
Initialize Vault:
vault operator init
IMPORTANT: Save the Unseal Keys and the Initial Root Token in a secure location. You will need them.
-
Unseal Vault: Use three of the five unseal keys generated in the previous step to unseal Vault. Run the following command three times with a different key each time:
vault operator unseal <UNSEAL_KEY>
-
Login with the Root Token:
vault login <INITIAL_ROOT_TOKEN>
Your Vault server is now ready. You can exit the container shell.
Now that Vault is running, you can use Terraform to provision the PKI infrastructure.
Navigate to the Terraform directory and create a terraform.tfvars file.
cd terraformYou can copy one of the examples from the tfvars directory or create your own. For a full PKI setup, your terraform.tfvars should look like this:
# terraform/terraform.tfvars
vault_addr = "https://127.0.0.1:8200"
vault_token = "<YOUR_INITIAL_ROOT_TOKEN>" # Replace with your Vault root token
company_name = "OMI Corp"
company_domain = "omi.corp"
# --- Control Switches ---
enable_pki = true
enable_pki_int = true
# Optional: Enable if you want to create leaf certificates
certificates_to_create = {
"web-server" = {
common_name = "web.omi.corp"
alt_names = ["web-server.omi.corp"]
ttl = "720h" # 30 days
}
}
# Optional: Enable for Kubernetes auth
# enable_k8s_auth = true
# clusters = [
# {
# name = "omik8s"
# vault_auth_path = "kubernetes-omik8s"
# kubernetes_host = "https://<K8S_API_SERVER_IP>:6443"
# kubernetes_ca_cert_path = "k8s_ca_certs/omik8s.ca.crt"
# token_reviewer_jwt_content = "<YOUR_SERVICE_ACCOUNT_JWT>"
# }
# ]Initialize, plan, and apply the Terraform configuration.
terraform init
terraform plan
terraform applyTerraform will connect to your Vault server and provision the Root CA, Intermediate CA, and any other configured resources.
.
├── config/
│ └── vault.hcl # Vault server configuration
├── docker-compose.yml # Docker Compose file for Vault and Minio
├── README.md # This file
├── ssl.sh # Script to generate self-signed TLS certs
├── terraform/
│ ├── main.tf # Main Terraform orchestration file
│ ├── variables.tf # Terraform input variables
│ ├── providers.tf # Terraform provider configuration
│ ├── modules/ # Reusable Terraform modules
│ │ ├── pki/ # Module for PKI Root CA
│ │ ├── pki_int/ # Module for PKI Intermediate CA
│ │ ├── k8s-auth/ # Module for Kubernetes auth
│ │ └── request-cert/ # Module for requesting leaf certs
│ └── tfvars/ # Example .tfvars files
└── tls/ # Generated TLS certificates (created by ssl.sh)