A complete Certificate Authority (CA) infrastructure implementation using OpenSSL, designed as both an educational showcase of PKI best practices and a practical tool for local development certificate generation.
This project serves two main purposes:
- Educational Showcase: Demonstrates how to properly set up a Certificate Authority infrastructure following industry best practices and security standards.
- Local Development Tool: Provides an easy way to generate trusted SSL/TLS certificates for local development environments, eliminating browser security warnings and enabling HTTPS testing.
This project implements a two-tier Certificate Authority structure following PKI best practices:
- Root CA: The trust anchor that signs the intermediate CA certificate.
- Intermediate CA: Signs end-entity certificates (servers, clients).
- Server Certificates: SSL/TLS certificates for web servers and applications.
The hierarchical approach provides better security by keeping the Root CA offline and using the Intermediate CA for day-to-day certificate signing operations.
├── root-ca/ # Root Certificate Authority
│ ├── certs/ # Root CA certificates
│ ├── csr/ # Certificate signing requests (for all services)
│ ├── newcerts/ # Newly issued certificates
│ └── openssl.cfg # Root CA OpenSSL configuration
├── intermediate-ca/ # Intermediate Certificate Authority
│ ├── certs/ # Intermediate CA certificates and chain
│ ├── csr/ # Certificate signing requests
│ ├── newcerts/ # Newly issued certificates
│ └── openssl.cfg # Intermediate CA OpenSSL configuration
├── server/ # Server certificates organized by service
│ ├── example/ # Example service
│ │ ├── openssl.cfg # Service-specific OpenSSL configuration
│ │ ├── private/ # Service private keys and PKCS#12 files
│ │ └── certs/ # Service certificates
│ └── [service-name]/ # Additional services follow the same pattern
│ ├── openssl.cfg
│ ├── private/
│ └── certs/
Build certificates for the Root CA and Intermediate CA:
make build_caThis command:
- Creates the Root CA private key and self-signed certificate (valid for 10 years)
- Creates the Intermediate CA private key and certificate signed by the Root CA
- Generates the certificate chain file for validation
Build certificate for the default service (example):
make build_serverOr build a certificate for a specific service:
make build_server SERVER_NAME=meshub
make build_server SERVER_NAME=api-gatewayYou can also use the script directly:
bash tools/build-server-certificate.sh example
bash tools/build-server-certificate.sh meshubTo add a new service:
-
Create the service directory:
mkdir -p server/my-service
-
Copy and customize the configuration:
cp server/example/openssl.cfg server/my-service/openssl.cfg
Edit
server/my-service/openssl.cfgwith your service-specific details (domain names, organization, etc.) -
Generate the certificate:
bash tools/build-server-certificate.sh my-service
This process:
- Creates a server private key for the specified service
- Generates a Certificate Signing Request (CSR)
- Issues the server certificate signed by the Intermediate CA
- Exports the certificate to PKCS#12 format for easy deployment
- Validates the certificate chain
- Stores files in
server/SERVICE_NAME/private/andserver/SERVICE_NAME/certs/
Verify the entire certificate chain (all services):
make verifyOr verify certificates for a specific service:
make verify_server # Verifies default service (example)
make verify_server SERVER_NAME=meshub # Verifies meshub serviceYou can also use the script directly:
bash tools/verify-certificates.sh # Verify all certificates
bash tools/verify-certificates.sh example # Verify example service only
bash tools/verify-certificates.sh meshub # Verify meshub service onlyThis validates:
- Root CA certificate format and integrity
- Intermediate CA certificate against Root CA
- Server certificate(s) against the certificate chain
To make certificates issued by your CA trusted system-wide on macOS:
make import_caThis command:
- Imports the Root CA certificate into the macOS System Keychain with
trustRootsetting - Imports the Intermediate CA certificate with
trustAsRootsetting - Requires sudo privileges (you'll be prompted for your password)
- Makes all certificates issued by this CA automatically trusted by:
- Web browsers (Safari, Chrome, Firefox)
- System applications
- Command-line tools (curl, wget, etc.)
You can also use the script directly:
bash tools/import-ca-certificates.shTo remove the imported CA certificates from the macOS System Keychain:
make remove_caThis command:
- Removes the Root CA certificate from the System Keychain
- Removes the Intermediate CA certificate from the System Keychain
- Requires sudo privileges
- Reverts the trust settings applied by
import_ca
You can also use the script directly:
bash tools/remove-ca-certificates.shAfter removal, certificates issued by this CA will no longer be automatically trusted. You may need to restart applications or clear browser caches for changes to take full effect.
Remove all generated certificates and temporary files:
make cleanThe project organizes certificates by service, making it easy to manage multiple applications:
# Generate certificates for different services
bash tools/build-server-certificate.sh api-gateway
bash tools/build-server-certificate.sh web-frontend
bash tools/build-server-certificate.sh database-service
# Verify specific services
bash tools/verify-certificates.sh api-gateway
bash tools/verify-certificates.sh web-frontendEach service has its own OpenSSL configuration file at server/SERVICE_NAME/openssl.cfg. You can customize:
- Organization details: Company name, organizational unit, location
- Subject Alternative Names (SAN): Domain names and IP addresses
- Certificate extensions: Key usage, extended key usage
Example SAN configuration in server/example/openssl.cfg:
[alternate_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
DNS.4 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.1.100- Root CA: 10 years (3650 days)
- Intermediate CA: 10 years (3650 days)
- Server certificates: 10 years (3650 days)
All certificates use:
- Key size: 3072-bit RSA
- Hash algorithm: SHA-256
- Proper file permissions: Private keys (400), Certificates (444)
# Generate certificates for multiple services
for service in api web database; do
bash tools/build-server-certificate.sh $service
done
# Verify all services
for service in api web database; do
bash tools/verify-certificates.sh $service
doneAfter running the build commands, certificates will be organized as follows:
- Root CA certificate:
root-ca/certs/ca.cert.pem - Root CA private key:
root-ca/private/ca.key.pem - Intermediate CA certificate:
intermediate-ca/certs/intermediate.cert.pem - Intermediate CA private key:
intermediate-ca/private/intermediate.key.pem - Certificate chain:
intermediate-ca/certs/ca-chain.cert.pem
For each service (e.g., example, meshub):
- Service certificate:
server/SERVICE_NAME/certs/DERIVED_NAME.cert.pem - Service private key:
server/SERVICE_NAME/private/DERIVED_NAME.key.pem - Service PKCS#12:
server/SERVICE_NAME/private/DERIVED_NAME.p12 - Service CSR:
root-ca/csr/DERIVED_NAME.csr.pem
Note: DERIVED_NAME is automatically generated from the commonName in the service's OpenSSL configuration (e.g., example.com becomes example-com).
server/
├── example/
│ ├── certs/example-com.cert.pem
│ └── private/
│ ├── example-com.key.pem
│ └── example-com.p12
└── meshub/
├── certs/meshub-us.cert.pem
└── private/
├── meshub-us.key.pem
└── meshub-us.p12
- This project demonstrates PKI concepts and provides certificates for local development
- Generated certificates are suitable for localhost, development servers, and learning environments
- The configuration prioritizes ease of use and educational value over production-grade security
- Private keys are stored with restrictive permissions (400)
- Root CA should be kept offline in production environments
- Intermediate CA handles day-to-day certificate signing
- Certificate serial numbers start from 1000
- All certificates use SHA-256 hashing
If adapting this for production use, consider:
- Hardware Security Modules (HSMs) for key storage
- Password-protected private keys
- Shorter certificate validity periods
- Proper key escrow and backup procedures
- Certificate Revocation Lists (CRL) and OCSP responders
- Audit logging and monitoring
- OpenSSL (tested with modern versions supporting 3072-bit RSA keys)
- Bash shell
- Make utility
tools/build-root-ca-certificate.sh- Creates the Root CAtools/build-intermediate-ca-certificate.sh- Creates the Intermediate CAtools/build-server-certificate.sh SERVICE_NAME- Creates certificates for a specific servicetools/verify-certificates.sh [SERVICE_NAME]- Verifies certificate chains
tools/import-ca-certificates.sh- Imports CA certificates into macOS System Keychaintools/remove-ca-certificates.sh- Removes CA certificates from macOS System Keychain
All scripts support:
-hor--help- Display usage information- Colored output for better readability
- Comprehensive error handling and validation
- Interactive prompts for overwriting existing certificates
- Permission denied errors: Ensure you have write permissions in the project directory
- OpenSSL command not found: Install OpenSSL on your system
- Service directory not found: Create the service directory and OpenSSL configuration first
- Certificate verification fails: Check that the certificate chain is properly built
- Invalid service name: Service names can only contain letters, numbers, dots, hyphens, and underscores
If you encounter issues with service certificates:
-
Check the OpenSSL configuration:
# Verify the config file exists and has proper format openssl req -config server/SERVICE_NAME/openssl.cfg -text -noout -
Verify the commonName is set:
grep "^commonName" server/SERVICE_NAME/openssl.cfg -
Check directory structure:
ls -la server/SERVICE_NAME/ # Should contain openssl.cfg
To rebuild everything from scratch:
make rebuildTo rebuild certificates for a specific service:
# Clean and rebuild specific service
rm -rf server/SERVICE_NAME/private server/SERVICE_NAME/certs
bash tools/build-server-certificate.sh SERVICE_NAMERemove all generated certificates and temporary files:
make clean # Clean all certificates
make clean_server SERVER_NAME=example # Clean specific service certificatesNote: The make clean command removes all generated certificates and keys. Use with caution in production environments.
# Setup CA infrastructure
make build_ca
# Generate service certificates
make build_server # Default service (example)
make build_server SERVER_NAME=meshub # Specific service
bash tools/build-server-certificate.sh my-service
# Verify certificates
make verify # All certificates
make verify_server # Default service
make verify_server SERVER_NAME=meshub # Specific service
bash tools/verify-certificates.sh my-service
# Import/Remove CA certificates (macOS)
make import_ca # Import CA certificates to System Keychain
make remove_ca # Remove CA certificates from System Keychain
bash tools/import-ca-certificates.sh # Direct script usage
bash tools/remove-ca-certificates.sh # Direct script usage
# Clean up
make clean # All certificates
make rebuild # Clean and rebuild all- Create service directory:
mkdir -p server/my-service - Copy configuration:
cp server/example/openssl.cfg server/my-service/ - Customize configuration: Edit
server/my-service/openssl.cfg - Generate certificate:
bash tools/build-server-certificate.sh my-service - Verify certificate:
bash tools/verify-certificates.sh my-service
This project is licensed under the MIT License - see the LICENSE file for details.
