# ๐ BundleCraft - Modern PKI Trust Store Builder






> โ ๏ธ **Important:** BundleCraft is currently in early pre-release (v0.x.x). The API, CLI, and docs may change as we iterate toward a stable v1.0.0. This is an independent, passion-driven project developed with a focus on practical PKI automation, secure engineering practices, and contributing back to the PKI community. Feedback welcome.
______________________________________________________________________
## โน๏ธ Overview
**BundleCraft** is a modern, configuration-as-code system for **fetching, building, verifying, and distributing multi-format certificate trust bundles** across environments. It securely sources certificate material from trusted remote origins or local files, then produces reproducible, auditable outputs for OS, Java, and application platforms.
Essentially, you configure the CA certificates you'd like to populate in your custom trust stores, and BundleCraft will take care of reliably converting them into consistent, multi-formatted trust bundle files you can then distribute to your servers, applications, and general infrastructure.
In short: BundleCraft lets ***you*** define how your PKI trust is built and configured.
______________________________________________________________________
## ๐ Quick Start
Get started with BundleCraft in under 5 minutes using either the container image or Python package!
> โ Before making full use of BundleCraft, you'll need a project & configuration structure for it to use. You can use [bundlecraft-starter](https://github.com/bundlecraft-io/bundlecraft-starter) to get going right away with a configuration structure and an out-of-the-box Github Actions workflow for building releases. Check out [bundlecraft-demo](https://github.com/bundlecraft-io/bundlecraft-demo) for a quick configuration example reference.
### Option 1: Using a Container
```bash
# Pull the latest container
podman pull ghcr.io/bundlecraft-io/bundlecraft:latest
# Create a basic project structure
mkdir my-ca-bundles && cd my-ca-bundles
mkdir -p cert_sources/internal config/envs config/sources
# Add your certificates
cp /path/to/your/root-ca.pem cert_sources/internal/
# Create a simple source config
cat > config/sources/internal.yaml << 'EOF'
---
apiVersion: bundlecraft.io/v1alpha1
kind: SourceConfig
source_name: internal
description: Internal CA certificates
repo:
- name: internal
include:
- cert_sources/internal/root-ca.pem
EOF
# Create an environment config
cat > config/envs/production.yaml << 'EOF'
---
apiVersion: bundlecraft.io/v1alpha1
kind: EnvConfig
name: Production Environment
bundles:
internal-prod:
include_sources: [internal]
output_formats:
- pem
- jks
- p12
- p7b
EOF
# Build your trust bundle
podman run --rm \
-v $(pwd)/config:/config \
-v $(pwd)/cert_sources:/cert_sources \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
build --env production --bundle internal-prod
# Verify the results
podman run --rm \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
verify --target /dist/production/internal-prod
```
### Option 2: Using Python Package
```bash
# Install BundleCraft
pip install bundlecraft
# Create project structure (same as above)
# ... (same directory and file creation as container example)
# Build your trust bundle
bundlecraft build --env production --bundle internal-prod
# Verify the results
bundlecraft verify --target dist/production/internal-prod
```
### What You Get
Every build produces a complete trust bundle in `dist/<environment>/<bundle>/`:
```text
bundlecraft-ca-trust.pem # Canonical PEM bundle
bundlecraft-ca-trust.jks # Java KeyStore
bundlecraft-ca-trust.p12 # PKCS#12 bundle
bundlecraft-ca-trust.p7b # PKCS#7 bundle
manifest.json # Build metadata & provenance
checksums.sha256 # Integrity verification
```
### Using Your Trust Bundles
Once built, deploy your certificate bundles across different platforms. Some generic examples (modify to the needs of your environment):
**Linux/Unix Systems:**
```bash
# Copy PEM bundle to system trust store
sudo cp bundlecraft-ca-trust.pem /etc/ssl/certs/custom-ca-bundle.pem
sudo update-ca-certificates
# Or for specific applications
export SSL_CERT_FILE=/path/to/bundlecraft-ca-trust.pem
```
**Java Applications:**
```bash
# Use JKS directly with Java applications
java -Djavax.net.ssl.trustStore=bundlecraft-ca-trust.jks \
-Djavax.net.ssl.trustStorePassword=changeit \
MyApplication
# Or import into existing Java cacerts
keytool -importkeystore -srckeystore bundlecraft-ca-trust.jks \
-destkeystore $JAVA_HOME/lib/security/cacerts
```
**Windows Systems:**
```powershell
# Import P12/PFX bundle to Windows Certificate Store
certlm.msc # Then import bundlecraft-ca-trust.p12 to Trusted Root CAs
# Or via PowerShell
Import-PfxCertificate -FilePath "bundlecraft-ca-trust.p12" `
-CertStoreLocation Cert:\LocalMachine\Root
```
**Container Images:**
```dockerfile
# Copy PEM bundle into container
COPY bundlecraft-ca-trust.pem /usr/local/share/ca-certificates/custom.crt
RUN update-ca-certificates
```
**Application Configuration:**
```yaml
# Example: Configure applications to use your trust bundle
tls:
ca_bundle: /etc/ssl/bundlecraft-ca-trust.pem
# or
truststore: /etc/ssl/bundlecraft-ca-trust.jks
truststore_password: changeit
```
______________________________________________________________________
## ๐ฏ Problems Solved
Managing certificate trust stores at scale is notoriously difficult. BundleCraft addresses the key pain points:
### ๐ **Manual, Error-Prone Trust Management**
- **Problem:** Teams manually copy/paste PEMs, run OpenSSL commands, and maintain separate keystores for different platforms. One wrong cert = outages.
- **Solution:** Single source of truth with versioned configs. Build once, export to all formats (PEM, JKS, P12, P7B, ZIP) automatically.
### ๐ **Format Fragmentation**
- **Problem:** Java needs JKS, Windows/IIS wants P12, Linux/Apache uses PEM, legacy systems require P7B. Keeping them synchronized is a nightmare.
- **Solution:** Universal converter that maintains certificate integrity across all formats. No more "works in dev, breaks in prod" due to format issues.
### ๐จ **Expired Certificate Surprises**
- **Problem:** Certs expire silently. No one knows until production fails at 3 AM.
- **Solution:** Built-in expiry validation with configurable warning thresholds. Fail builds early, prevent runtime disasters.
### ๐ข **Environment-Specific Trust Requirements**
- **Problem:** Dev needs test CAs, QA needs staging roots, Prod requires only production-approved CAs. Managing this across teams is chaos.
- **Solution:** Layered configuration model (defaults โ environment โ bundle) keeps trust policies explicit and environment-aware.
### ๐ **Zero Auditability**
- **Problem:** "Who added this cert? When? Why?" No one knows. Compliance nightmares during audits.
- **Solution:** Every build produces manifest.json with full provenance, checksums.sha256 for integrity, and optional GPG signatures. Complete audit trail.
### ๐ **Non-Reproducible Builds**
- **Problem:** "It works on my machine" but fails in CI. Different Python versions, missing tools, inconsistent outputs.
- **Solution:** Configuration-as-code with deterministic builds. Same inputs = same outputs, every time. Perfect for GitOps workflows.
______________________________________________________________________
## โจ Features
- **Multiple installation methods**: Container image (recommended) or Python package via PyPI
- **Trusted Fetch layer**: Securely fetch certificates from HTTPS, APIs, and Vault with CA/fingerprint/sha256 pinning; staging-only (no cache) and full provenance.
- **Reproducible builds** using layered YAML configs
- **Multi-format export:** PEM, P7B, JKS, P12, ZIP
- **Cross-format verification:** expiry, empties, count consistency
- **Extensible config model:** defaults โ environment โ bundle
- **Portable tooling:** Pure Python, no system dependencies like OpenSSL or JDK needed
- **Manifest and checksum generation:** for auditing and release integrity
- **SBOM generation:** CycloneDX SBOM for supply chain transparency (enabled by default; can be disabled)
- **Sigstore signing:** All releases (container images and PyPI packages) are cryptographically signed with Sigstore for supply chain security
- **GPG signing integration:** Sign release artifacts with detached signatures (`--sign`)
- **Signature verification:** Built-in verification for signed releases (see Verifier)
- **CI/CD ready:** Designed for (but not exclusive to) GitHub Actions, supports concurrency and artifact management
- **Flexible bundle and environment definitions**: Easily add new trust bundles or environments
______________________________________________________________________
## ๐ Key Outputs Each Build
- Canonical **PEM** bundle (with annotated subjects, deduplication)
- **PKCS#7 (.p7b)** - DER-encoded bundle
- **Java KeyStore (.jks)** - per-cert aliasing, password-protected
- **PKCS#12 (.p12/.pfx)** - multi-cert export, password-protected
- **ZIP** (tarball of all files)
- Deterministic **manifest.json** and **checksums.sha256** (traceability)
- **SBOM (Software Bill of Materials)** in CycloneDX format (optional, on by default)
- **GPG signatures (.asc)** for all artifacts (optional, when `--sign`)
### ๐ Sigstore-Signed Releases
All official BundleCraft releases are signed with [Sigstore](https://sigstore.dev) for verifiable supply chain security:
- **Container images**: Signed with [cosign](https://docs.sigstore.dev/cosign/overview/) using keyless OIDC signing
- **PyPI packages**: Include Sigstore attestations via PyPI Trusted Publishing
To verify a container image signature:
```bash
cosign verify ghcr.io/bundlecraft-io/bundlecraft:latest \
--certificate-identity-regexp="https://github.com/bundlecraft-io/bundlecraft" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
See [CONTRIBUTING.md](CONTRIBUTING.md#verifying-sigstore-signatures) for complete verification instructions.
______________________________________________________________________
## ๐๏ธ How It Works
### Overview
BundleCraft uses a **layered configuration model** and a three-stage pipeline when performing a `bundlecraft build`, its core operation:
`fetch/source โ convert โ verify`
BundleCraft provides the building blocks for trust bundle creation, while your CI/CD environment orchestrates the broader workflow:
`discover โ build โ collect โ publish`
**Configuration Overview:**
1. **Defaults** (`config/defaults.yaml`):
Global settings (verification, filters, formats)
1. **Environments** (`config/envs/<env>.yaml`):
Contextual overrides (paths, secrets, output formats, targets)
1. **Sources** (`config/cert_sources/<source>.yaml`):
Bundle content definition (certificate sources to include/exclude)
- **Fetch** (`fetch:` in `<source>`): Securely fetch and stage certificates under `cert_sources/staged/<source_name>/fetch/<name>/`. Local includes are staged under `cert_sources/staged/<source_name>/<repo_name>/` (or `include/` for legacy). Staging is cleaned each run; no persistent cache.
**Flow:**
- Merge config layers: defaults โ env โ bundle
- If `fetch:` is present, securely stage remote sources under `cert_sources/staged/<source_name>/fetch/<name>/` with provenance
- Deduplicate, verify, and annotate certs
- Generate canonical PEM bundle
- Convert to supplemental formats, JKS, P7B, etc.
- Generate `manifest.json` and `checksums.sha256`
- Package build into `.tar.gz` tarball if configured
- Verify all outputs and cross-format consistency
- Optionally sign and publish release artifacts
### Fetch Layer & External Integrations
BundleCraft's optional **Fetch layer** enables secure retrieval of certificates from external systems, allowing you to build trust bundles from remote sources while maintaining full security and auditability.
**Supported Integrations:**
- **๐ HTTPS URLs** - Mozilla CA bundle, public certificate repositories
- **๐ HashiCorp Vault** - Certificate storage in Vault KV stores or PKI secrets engines
- **๐ Custom APIs** - Generic REST API support with configurable authentication
**Security Features:**
- HTTPS-only with optional CA pinning and TLS fingerprint validation
- Content integrity verification with SHA256 checksums
- Full provenance tracking for compliance and audit requirements
- Staging-only approach with no persistent caching
All fetchers support token-based authentication via environment variables and include comprehensive error handling. See [docs/fetchers.md](docs/fetchers.md) for detailed configuration examples and security best practices.
______________________________________________________________________
## โก Quick CLI Reference
For more detailed usage and options, see [`bundlecraft/README.md`](bundlecraft/README.md).
### Core CLI
All commands work with both the Python package (`bundlecraft`) and container (`podman run ghcr.io/bundlecraft-io/bundlecraft:latest`):
|Command|Purpose|Example Usage|
|---|---|---|
| `bundlecraft fetch` | Securely fetch remote sources and stage them (no persistent cache) | `bundlecraft fetch --env prod --bundle internal` |
| `bundlecraft build` | Build trust bundles from configs, write all outputs | `bundlecraft build --env prod --bundle internal-prod` |
| `bundlecraft build-all` | Discover and build all environments; supports scoping and plan output | `bundlecraft build-all --envs-path teamA --print-plan` |
| `bundlecraft verify` | Verify PEMs or built bundle directories (expiry + integrity) | `bundlecraft verify dist/prod/internal --verify-all` |
| `bundlecraft diff` | Compare two bundles and identify certificate changes | `bundlecraft diff --from dist/prod/v1/internal --to dist/prod/v2/internal` |
| `bundlecraft convert` | Convert any supported input to any supported output (PEM, P7B, JKS, P12, ZIP) | `bundlecraft convert --input bundlecraft-ca-trust.pem --output-dir ./ --output-format jks` |
### Common Commands
#### Using Python Package
```bash
# Build all bundles in the production environment
bundlecraft build --env prod
# Build only the internal bundle in the production environment
bundlecraft build --env prod --bundle internal
# Verify a bundle
bundlecraft verify --target dist/prod/internal --verify-all
# Compare two bundles (identify certificate changes)
bundlecraft diff --from dist/prod/v1/internal --to dist/prod/v2/internal
# Convert formats
bundlecraft convert --input bundlecraft-ca-trust.pem --output-dir ./ --output-format jks
```
#### Using Container
```bash
# Build with container (mount volumes for config, sources, and output)
podman run --rm \
-v $(pwd)/config:/config \
-v $(pwd)/cert_sources:/cert_sources \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
build --env prod --bundle internal
# Verify with container
podman run --rm \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
verify --target /dist/prod/internal --verify-all
# Convert formats with container
podman run --rm \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
convert --input /dist/bundlecraft-ca-trust.pem --output-dir /dist --output-format jks
```
### Machine-Readable Output (JSON)
All BundleCraft commands support `--json` flag for CI/CD automation and scripting:
```bash
# Get structured output for automation
bundlecraft build --env prod --bundle mozilla --json | jq .
# Parse specific fields in scripts
SUCCESS=$(bundlecraft fetch --source-config-file config/cert_sources/mozilla.yaml --json | jq -r '.success')
if [ "$SUCCESS" = "true" ]; then
echo "Fetch succeeded"
fi
# Extract verification results
bundlecraft verify --target dist/prod/mozilla --json | jq -r '.verified_files'
```
- ๐ **Full documentation:** [docs/JSON-OUTPUT.md](docs/JSON-OUTPUT.md)
- ๐ **Examples:** [scripts/json-output-examples.sh](scripts/json-output-examples.sh)
______________________________________________________________________
## โ๏ธ Configuration
### Config Files
#### Source Config (`config/cert_sources/*.yaml`)
These configuration files are your **trusted certificate sources.**
It defines where BundleCraft where retrieve CA certificates from and stage them for a build. These certificates can either come from:
- `repo`: a locally committed source, useful for simplicity or if you'd like explicit control of which exact certificates are built from within the repository, along with the rest of `bundlecraft` build configuration.
- `fetch`: a trusted remote source, such as HashiCorp Vault, Keyfactor Command, or the Mozilla CA Bundle from [curl.se](https://curl.se/docs/caextract.html). Useful when managing trusted certificates in separate systems, while still being able to use `bundlecraft` configuration to perform further filtering.
These bundles are then referenced by environment configuration files, which will go on to define which bundles these sourced certificates will appear in.
```yaml
# Optional, recommended identifiers for future controller/CRD-style tooling
apiVersion: bundlecraft.io/v1alpha1
kind: SourceConfig
bundle_name: internal
description: Trust bundle for internal PKI services
repo:
- name: internal
include:
# Path entries (string or {path: ...})
- cert_sources/internal/rootCA.pem
- { path: cert_sources/internal/issuingCA1.pem }
# Inline PEM entry (optional name; if omitted, a name is generated)
- name: special-inline.pem
inline: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
# Optional remote sources (fetched at build time, staged with provenance)
fetch:
- name: mozilla_roots
type: url
url: https://curl.se/ca/cacert.pem
metadata:
# Free-form documentation and selectors
owner: example@bundlecraft.io
tags: [internal]
labels: { team: security, tier: core }
```
#### Environment Config (`config/envs/*.yaml`)
Defines **how** bundles are built in a specific context, including secrets, output path, global filters, and format behavior.
These configuration files are your **customized certificate trust bundles.**
It defines how BundleCraft (based on the certificate source configurations from `config/cert_sources/`) will build, merge, package, and prepare your trust bundle files for distribution. These are essentially your environment specific configuration files.
Additional build filters, verification guardrails, packaging settings, and formatting options can be specified here.
```yaml
# Optional, recommended identifiers
apiVersion: bundlecraft.io/v1alpha1
kind: EnvConfig
name: Example Environment
build_path: dist/example/
package: false
verify:
fail_on_expired: true
warn_days_before_expiry: 30
output_formats:
- pem
- p7b
- jks
- p12
format_overrides:
jks:
storepass_env: TRUST_JKS_PASSWORD
alias_format: "{subject.CN}-{serial}"
pkcs12:
password_env: TRUST_P12_PASSWORD
filters:
unique_by_fingerprint: true
not_expired_only: true
ca_certs_only: true
metadata:
contact: security@bundlecraft.io
policy_version: 1.0
```
Notes on config headers and metadata
- `apiVersion` and `kind` are optional but validated when present. They futureโproof configs for strict environments (e.g., Kubernetes-style controllers) without changing behavior.
- `metadata.labels` is supported on source and environment configs to attach machine-readable key/value tags for internal automation. Itโs not used for selection today (envs reference sources by name only) but provides a clean place for future selectors and CI policies.
- Separation of concerns is enforced: environment configs compose sources by name and control build/distribution; source configs own repo/fetch definitions. Envs do not reference nested repo/fetch entries.
#### Defaults (`config/defaults.yaml`)
Baseline settings for verification, filters, output formats, and metadata.
These can be overridden by environment or source configs.
### Environment Variables
BundleCraft supports the following environment variables for configuration:
| Variable | Purpose | Default Value | Used By |
|------------------------|-----------------------------------------------|----------------|------------------|
| `TRUST_JKS_PASSWORD` | Password for Java KeyStore operations | `"changeit"` | Convert, Verify |
| `TRUST_P12_PASSWORD` | Password for PKCS#12 operations | `"changeit"` | Convert, Verify |
| `BUNDLECRAFT_WORKSPACE` | Override workspace directory for builds | Current directory | Builder |
| `VAULT_TOKEN` | HashiCorp Vault authentication token | - | Vault Fetcher |
| `VAULT_ADDR` | HashiCorp Vault server address | - | Vault Fetcher |
| `KEYFACTOR_TOKEN` | Keyfactor API authentication token | - | API Fetcher |
| `GPG_KEY_ID` | GPG key identifier for signing operations | - | Signing |
| `GPG_PASSPHRASE` | GPG key passphrase for signing | `""` (empty) | Signing |
**Note:**
- Password variables are used as fallback values and can be overridden via CLI options or config files
- Authentication tokens (`*_TOKEN`) are required when using their respective fetchers
- Signing variables are only needed when using `--sign` option
- Workspace variable is primarily used for development and testing environments
______________________________________________________________________
## ๐ Security & Verification
- **Strict Expiry Handling:** Build fails if any cert is expired (unless configured otherwise)
- **Deduplication:** SHA256 fingerprint used for unique certs
- **Subject Annotation:** PEM includes `# Subject:` comments for traceability
- **Manifest & Checksums:** Every build records outputs with SHA256 in both JSON and text formats
- **Cross-format Verification:** Cert counts and file integrity checked for PEM, P7B, JKS, P12
- **Fetch provenance:** `provenance.fetch.json` recorded in staging and embedded into `manifest.json` under `fetched`
- **Network trust controls:** HTTPS only (for APIs and URLs), optional custom CA, optional TLS leaf fingerprint pinning, and optional content `sha256` pinning
- **GPG signing:** Sign all release artifacts with detached GPG signatures (.asc files)
- **SBOM generation:** Automatic Software Bill of Materials in CycloneDX format
- **Signature verification:** Built-in verification for signed releases with keyring support
- **Dependency lock file:** Production builds use exact dependency versions from `requirements-lock.txt` for reproducibility (see [CONTRIBUTING.md](./CONTRIBUTING.md#dependency-lock-file))
For more, see: [`SECURITY.md`](./SECURITY.md)
______________________________________________________________________
## โ๐ฝ Signing Release Artifacts
Optionally, sign all release artifacts with GPG during your build for verification later on:
```bash
# Generate or use existing GPG key
gpg --full-generate-key
# Build and sign artifacts
export GPG_KEY_ID=ABCD1234EFGH5678
bundlecraft build --env prod --bundle mozilla --sign
# Verify signatures
bundlecraft verify --target dist/Production/mozilla --verify-signatures
```
See [SIGNING-AND-SBOM.md](docs/SIGNING-AND-SBOM.md) for the complete guide on:
- GPG key generation and management
- CI/CD integration with GitHub Actions
- SBOM usage and validation
- Key management best practices
______________________________________________________________________
## ๐งญ Troubleshooting & FAQ
### Container Issues
**Container volume mount issues?**
Ensure volumes are mounted correctly:
```bash
podman run --rm \
-v $(pwd)/config:/config \
-v $(pwd)/cert_sources:/cert_sources \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
build --env prod
```
- **Verifier says JKS=0?**
Ensure password is correct. The default password is `"changeit"`. Set `TRUST_JKS_PASSWORD` env var if using a different password.
```bash
podman run --user $(id -u):$(id -g) --rm \
-v $(pwd)/config:/config \
-v $(pwd)/cert_sources:/cert_sources \
-v $(pwd)/dist:/dist \
ghcr.io/bundlecraft-io/bundlecraft:latest \
build --env prod
```
### Format & Conversion Issues
**Empty P7B files?**
Ensure your PEM input files contain valid certificates. BundleCraft uses the Python `cryptography` module for all format conversions.
**P12 only contains one certificate?**
This has been fixed in the current version - all certificates from the bundle are included in the PKCS#12 output.
**Duplicate JKS aliases?**
The build process removes existing keystores before import to prevent conflicts. Ensure you're using the latest version.
### Authentication & Secrets
**Password issues with keystores?**
Default passwords are `"changeit"` for both JKS and P12 formats. Override with environment variables:
```bash
export TRUST_JKS_PASSWORD="your-jks-password" #pragma: allowlist secret
export TRUST_P12_PASSWORD="your-p12-password" #pragma: allowlist secret
bundlecraft build --env prod
```
**Vault authentication failing?**
Ensure both `VAULT_TOKEN` and `VAULT_ADDR` are set:
```bash
export VAULT_TOKEN="hvs.your-vault-token"
export VAULT_ADDR="https://vault.example.com:8200"
```
**Keyfactor API authentication issues?**
Set the `KEYFACTOR_TOKEN` environment variable:
```bash
export KEYFACTOR_TOKEN="your-keyfactor-api-token"
```
### Network & Fetch Issues
**"Insecure HTTP rejected" errors?**
BundleCraft only supports HTTPS for security. Use `https://` URLs or `file://` for local files. For APIs, configure proper CA verification:
```yaml
fetch:
- name: secure_source
type: api
endpoint: https://api.example.com/certificates
verify:
ca_file: config/certs/api-ca.pem
tls_fingerprint_sha256: "abc123..." # optional
```
**SHA256 content mismatch errors?**
Update the expected `verify.sha256` value to match the current content, or investigate if the source has changed unexpectedly:
```yaml
verify:
sha256: "new-expected-sha256-hash"
```
**TLS fingerprint mismatch errors?**
Re-check the server certificate fingerprint (leaf certificate). If it rotated legitimately, update the configuration:
```yaml
verify:
tls_fingerprint_sha256: "new-leaf-certificate-fingerprint"
```
When using containers, Vault support is included by default.
### Build & Configuration Issues
**Offline builds needed?**
Use `bundlecraft build --skip-fetch` to avoid network access. If your config includes `fetch:` sections, pre-stage certificates:
```bash
# In connected environment
bundlecraft fetch --env prod
# Commit or package staged inputs
# Then in offline environment
bundlecraft build --env prod --skip-fetch
```
**Configuration validation errors?**
Check YAML syntax and ensure all required fields are present. Use the `--verbose` flag for detailed error information:
```bash
bundlecraft build --env prod --verbose
```
**Certificate expiry warnings or failures?**
Configure expiry handling in your environment config:
```yaml
verify:
fail_on_expired: false # Don't fail builds on expired certs
warn_days_before_expiry: 30 # Warn 30 days before expiry
```
### Common Commands for Debugging
```bash
# Verbose output for detailed error information
bundlecraft build --env prod --verbose
# JSON output for structured error parsing
bundlecraft build --env prod --json
# Verify a specific bundle with detailed output
bundlecraft verify --target dist/prod/internal --verify-all --verbose
# Test fetch configuration without building
bundlecraft fetch --env prod --bundle internal --verbose
```
### Additional Resources
For more detailed troubleshooting information, see:
- ๐ [Complete Troubleshooting Guide](docs/troubleshooting.md)
- ๐ง [Configuration Specification](docs/CONFIG-SPEC.md)
- ๐ซ [Anti-Patterns Guide](docs/ANTI-PATTERNS.md)
- ๐ฌ [GitHub Discussions](https://github.com/bundlecraft-io/bundlecraft/discussions) for community support
______________________________________________________________________
## ๐ฎ Philosophy & Best Practices
### Philosophy
BundleCraft treats certificate trust management as a holistic engineering problem requiring reproducibility, auditability, and security at every layer. Rather than just being another certificate conversion tool, BundleCraft provides a complete configuration-as-code approach to trust store management.
**Core Design Principles:**
- **Declarative configuration:** Define what you want, not how to get it - BundleCraft handles the complexity
- **Reproducible builds:** Same inputs always produce identical outputs across environments and time
- **Defense in depth:** Multiple verification layers from source validation to output integrity checking
- **Full provenance:** Every operation is tracked and auditable for compliance and debugging
- **Environment awareness:** Support different trust requirements across dev, staging, and production
- **Format agnostic:** Universal trust bundle that works across all platforms and technologies
### Best Practices
**Security:**
- Always use HTTPS; never `http://`
- Pin content (`verify.sha256`) for static/public bundles when possible (e.g., Mozilla)
- For APIs/services, prefer TLS CA pinning and optionally leaf fingerprint pinning
- Keep tokens in env vars (`*_TOKEN`) and never commit secrets in YAML
**Configuration Management:**
- Commit sample configs but not secrets; use CI secret stores for tokens
- Treat `cert_sources/staged/` as ephemeral; do not rely on it as a cache
- Use layered configs: defaults โ environment โ bundle for clean separation
- Test configurations in non-production environments first
**Operational:**
- Use `--json` output for CI/CD automation and monitoring
- Implement certificate expiry monitoring with configurable thresholds
- Regularly verify bundle integrity across all environments
- Document your certificate sources and approval processes
______________________________________________________________________
## ๐ Additional Documentation
For topics not discussed in this README, or for topics that need their own page.
**See: [`docs/README.md`](docs/README.md)**
______________________________________________________________________
## ๐ค Contributing
- Issues and PRs are welcome!
- Check out [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) before getting started for come community guidelines.
- See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to interact with the codebase and release process.
______________________________________________________________________
## ๐ Changelog
See [CHANGELOG.md](https://github.com/bundlecraft-io/bundlecraft/blob/main/CHANGELOG.md) for release history and what's changed between versions.
______________________________________________________________________
## ๐ท๏ธ Tags & Metadata
- **Topics:** python, tls, cli, security, cryptography, openssl, certificates, x509, pki, keystore, pem, cicd, bundles, devsecops, truststore, ca-certificates, certificate-management, pki-tools
______________________________________________________________________
## ๐ Related Projects & References
**BundleCraft Ecosystem:**
- [๐งฑ BundleCraft Starter](https://github.com/bundlecraft-io/bundlecraft-starter) - Template repository with GitHub Actions workflow for orchestrating your own BundleCraft builds.
- [๐ง๐ฝโ๐ป BundleCraft Demo](https://github.com/bundlecraft-io/bundlecraft-demo) - Mock environment for showcasing BundleCraft's usages and potential applications in the format of sample scenario.
**Standards & Documentation:**
- [RFC 5280 - Internet X.509 PKI Certificate and CRL Profile](https://datatracker.ietf.org/doc/html/rfc5280)
- [RFC 5652 - Cryptographic Message Syntax (CMS / PKCS#7)](https://datatracker.ietf.org/doc/html/rfc5652)
- [RFC 7292 - PKCS #12 v1.1 (Personal Information Exchange)](https://datatracker.ietf.org/doc/html/rfc7292)
- [Python cryptography library documentation](https://cryptography.io/)
______________________________________________________________________
## ๐ Acknowledgements
Certificates are easy. Certificate management is hard.
Special thanks to all the security and infrastructure teams out there, whose collective experience and guidance has fueled this project.
______________________________________________________________________
## ๐ฃ Questions?
Open an [issue](https://github.com/bundlecraft-io/bundlecraft/issues)
or reach out via [GitHub Discussions](https://github.com/bundlecraft-io/bundlecraft/discussions)
______________________________________________________________________
ยฉ 2025 BundleCraft.io
Licensed under the [MIT License](./LICENSE).
> Made with โค๏ธ (and โ) for anyone whoโs ever debugged a broken trust chain.
> BundleCraft is a passion project, built to make certificate trust a little less painful for everyone.
> Contributions, ideas, and curiosity are always welcome.
Raw data
{
"_id": null,
"home_page": null,
"name": "bundlecraft",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "\"BundleCraft.io\" <hello@bundlecraft.io>",
"keywords": "ca-bundle, certificates, cryptography, pki, security, trust-store",
"author": null,
"author_email": "\"BundleCraft.io\" <hello@bundlecraft.io>",
"download_url": "https://files.pythonhosted.org/packages/7a/60/8ebc515d496c4172b56df45bd118ea72c5e42da2900e07ab72e94d8eb2d9/bundlecraft-0.3.0.tar.gz",
"platform": null,
"description": "# \ud83d\udd10 BundleCraft - Modern PKI Trust Store Builder\n\n\n\n\n\n\n\n\n> \u26a0\ufe0f **Important:** BundleCraft is currently in early pre-release (v0.x.x). The API, CLI, and docs may change as we iterate toward a stable v1.0.0. This is an independent, passion-driven project developed with a focus on practical PKI automation, secure engineering practices, and contributing back to the PKI community. Feedback welcome.\n\n______________________________________________________________________\n\n## \u2139\ufe0f Overview\n\n**BundleCraft** is a modern, configuration-as-code system for **fetching, building, verifying, and distributing multi-format certificate trust bundles** across environments. It securely sources certificate material from trusted remote origins or local files, then produces reproducible, auditable outputs for OS, Java, and application platforms.\n\nEssentially, you configure the CA certificates you'd like to populate in your custom trust stores, and BundleCraft will take care of reliably converting them into consistent, multi-formatted trust bundle files you can then distribute to your servers, applications, and general infrastructure.\n\nIn short: BundleCraft lets ***you*** define how your PKI trust is built and configured.\n\n______________________________________________________________________\n\n## \ud83d\ude80 Quick Start\n\nGet started with BundleCraft in under 5 minutes using either the container image or Python package!\n\n> \u2757 Before making full use of BundleCraft, you'll need a project & configuration structure for it to use. You can use [bundlecraft-starter](https://github.com/bundlecraft-io/bundlecraft-starter) to get going right away with a configuration structure and an out-of-the-box Github Actions workflow for building releases. Check out [bundlecraft-demo](https://github.com/bundlecraft-io/bundlecraft-demo) for a quick configuration example reference.\n\n### Option 1: Using a Container\n\n```bash\n# Pull the latest container\npodman pull ghcr.io/bundlecraft-io/bundlecraft:latest\n\n# Create a basic project structure\nmkdir my-ca-bundles && cd my-ca-bundles\nmkdir -p cert_sources/internal config/envs config/sources\n\n# Add your certificates\ncp /path/to/your/root-ca.pem cert_sources/internal/\n\n# Create a simple source config\ncat > config/sources/internal.yaml << 'EOF'\n---\napiVersion: bundlecraft.io/v1alpha1\nkind: SourceConfig\nsource_name: internal\ndescription: Internal CA certificates\nrepo:\n - name: internal\n include:\n - cert_sources/internal/root-ca.pem\nEOF\n\n# Create an environment config\ncat > config/envs/production.yaml << 'EOF'\n---\napiVersion: bundlecraft.io/v1alpha1\nkind: EnvConfig\nname: Production Environment\nbundles:\n internal-prod:\n include_sources: [internal]\noutput_formats:\n - pem\n - jks\n - p12\n - p7b\nEOF\n\n# Build your trust bundle\npodman run --rm \\\n -v $(pwd)/config:/config \\\n -v $(pwd)/cert_sources:/cert_sources \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n build --env production --bundle internal-prod\n\n# Verify the results\npodman run --rm \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n verify --target /dist/production/internal-prod\n```\n\n### Option 2: Using Python Package\n\n```bash\n# Install BundleCraft\npip install bundlecraft\n\n# Create project structure (same as above)\n# ... (same directory and file creation as container example)\n\n# Build your trust bundle\nbundlecraft build --env production --bundle internal-prod\n\n# Verify the results\nbundlecraft verify --target dist/production/internal-prod\n```\n\n### What You Get\n\nEvery build produces a complete trust bundle in `dist/<environment>/<bundle>/`:\n\n```text\nbundlecraft-ca-trust.pem # Canonical PEM bundle\nbundlecraft-ca-trust.jks # Java KeyStore\nbundlecraft-ca-trust.p12 # PKCS#12 bundle\nbundlecraft-ca-trust.p7b # PKCS#7 bundle\nmanifest.json # Build metadata & provenance\nchecksums.sha256 # Integrity verification\n```\n\n### Using Your Trust Bundles\n\nOnce built, deploy your certificate bundles across different platforms. Some generic examples (modify to the needs of your environment):\n\n**Linux/Unix Systems:**\n\n```bash\n# Copy PEM bundle to system trust store\nsudo cp bundlecraft-ca-trust.pem /etc/ssl/certs/custom-ca-bundle.pem\nsudo update-ca-certificates\n\n# Or for specific applications\nexport SSL_CERT_FILE=/path/to/bundlecraft-ca-trust.pem\n```\n\n**Java Applications:**\n\n```bash\n# Use JKS directly with Java applications\njava -Djavax.net.ssl.trustStore=bundlecraft-ca-trust.jks \\\n -Djavax.net.ssl.trustStorePassword=changeit \\\n MyApplication\n\n# Or import into existing Java cacerts\nkeytool -importkeystore -srckeystore bundlecraft-ca-trust.jks \\\n -destkeystore $JAVA_HOME/lib/security/cacerts\n```\n\n**Windows Systems:**\n\n```powershell\n# Import P12/PFX bundle to Windows Certificate Store\ncertlm.msc # Then import bundlecraft-ca-trust.p12 to Trusted Root CAs\n\n# Or via PowerShell\nImport-PfxCertificate -FilePath \"bundlecraft-ca-trust.p12\" `\n -CertStoreLocation Cert:\\LocalMachine\\Root\n```\n\n**Container Images:**\n\n```dockerfile\n# Copy PEM bundle into container\nCOPY bundlecraft-ca-trust.pem /usr/local/share/ca-certificates/custom.crt\nRUN update-ca-certificates\n```\n\n**Application Configuration:**\n\n```yaml\n# Example: Configure applications to use your trust bundle\ntls:\n ca_bundle: /etc/ssl/bundlecraft-ca-trust.pem\n # or\n truststore: /etc/ssl/bundlecraft-ca-trust.jks\n truststore_password: changeit\n```\n\n______________________________________________________________________\n\n## \ud83c\udfaf Problems Solved\n\nManaging certificate trust stores at scale is notoriously difficult. BundleCraft addresses the key pain points:\n\n### \ud83d\udcdd **Manual, Error-Prone Trust Management**\n\n- **Problem:** Teams manually copy/paste PEMs, run OpenSSL commands, and maintain separate keystores for different platforms. One wrong cert = outages.\n- **Solution:** Single source of truth with versioned configs. Build once, export to all formats (PEM, JKS, P12, P7B, ZIP) automatically.\n\n### \ud83d\udd04 **Format Fragmentation**\n\n- **Problem:** Java needs JKS, Windows/IIS wants P12, Linux/Apache uses PEM, legacy systems require P7B. Keeping them synchronized is a nightmare.\n- **Solution:** Universal converter that maintains certificate integrity across all formats. No more \"works in dev, breaks in prod\" due to format issues.\n\n### \ud83d\udea8 **Expired Certificate Surprises**\n\n- **Problem:** Certs expire silently. No one knows until production fails at 3 AM.\n- **Solution:** Built-in expiry validation with configurable warning thresholds. Fail builds early, prevent runtime disasters.\n\n### \ud83c\udfe2 **Environment-Specific Trust Requirements**\n\n- **Problem:** Dev needs test CAs, QA needs staging roots, Prod requires only production-approved CAs. Managing this across teams is chaos.\n- **Solution:** Layered configuration model (defaults \u2192 environment \u2192 bundle) keeps trust policies explicit and environment-aware.\n\n### \ud83d\udd0d **Zero Auditability**\n\n- **Problem:** \"Who added this cert? When? Why?\" No one knows. Compliance nightmares during audits.\n- **Solution:** Every build produces manifest.json with full provenance, checksums.sha256 for integrity, and optional GPG signatures. Complete audit trail.\n\n### \ud83d\udd01 **Non-Reproducible Builds**\n\n- **Problem:** \"It works on my machine\" but fails in CI. Different Python versions, missing tools, inconsistent outputs.\n- **Solution:** Configuration-as-code with deterministic builds. Same inputs = same outputs, every time. Perfect for GitOps workflows.\n\n______________________________________________________________________\n\n## \u2728 Features\n\n- **Multiple installation methods**: Container image (recommended) or Python package via PyPI\n- **Trusted Fetch layer**: Securely fetch certificates from HTTPS, APIs, and Vault with CA/fingerprint/sha256 pinning; staging-only (no cache) and full provenance.\n- **Reproducible builds** using layered YAML configs\n- **Multi-format export:** PEM, P7B, JKS, P12, ZIP\n- **Cross-format verification:** expiry, empties, count consistency\n- **Extensible config model:** defaults \u2192 environment \u2192 bundle\n- **Portable tooling:** Pure Python, no system dependencies like OpenSSL or JDK needed\n- **Manifest and checksum generation:** for auditing and release integrity\n- **SBOM generation:** CycloneDX SBOM for supply chain transparency (enabled by default; can be disabled)\n- **Sigstore signing:** All releases (container images and PyPI packages) are cryptographically signed with Sigstore for supply chain security\n- **GPG signing integration:** Sign release artifacts with detached signatures (`--sign`)\n- **Signature verification:** Built-in verification for signed releases (see Verifier)\n- **CI/CD ready:** Designed for (but not exclusive to) GitHub Actions, supports concurrency and artifact management\n- **Flexible bundle and environment definitions**: Easily add new trust bundles or environments\n\n______________________________________________________________________\n\n## \ud83d\udd11 Key Outputs Each Build\n\n- Canonical **PEM** bundle (with annotated subjects, deduplication)\n- **PKCS#7 (.p7b)** - DER-encoded bundle\n- **Java KeyStore (.jks)** - per-cert aliasing, password-protected\n- **PKCS#12 (.p12/.pfx)** - multi-cert export, password-protected\n- **ZIP** (tarball of all files)\n- Deterministic **manifest.json** and **checksums.sha256** (traceability)\n- **SBOM (Software Bill of Materials)** in CycloneDX format (optional, on by default)\n- **GPG signatures (.asc)** for all artifacts (optional, when `--sign`)\n\n### \ud83d\udd10 Sigstore-Signed Releases\n\nAll official BundleCraft releases are signed with [Sigstore](https://sigstore.dev) for verifiable supply chain security:\n\n- **Container images**: Signed with [cosign](https://docs.sigstore.dev/cosign/overview/) using keyless OIDC signing\n- **PyPI packages**: Include Sigstore attestations via PyPI Trusted Publishing\n\nTo verify a container image signature:\n```bash\ncosign verify ghcr.io/bundlecraft-io/bundlecraft:latest \\\n --certificate-identity-regexp=\"https://github.com/bundlecraft-io/bundlecraft\" \\\n --certificate-oidc-issuer=https://token.actions.githubusercontent.com\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md#verifying-sigstore-signatures) for complete verification instructions.\n\n______________________________________________________________________\n\n## \ud83c\udfd7\ufe0f How It Works\n\n### Overview\n\nBundleCraft uses a **layered configuration model** and a three-stage pipeline when performing a `bundlecraft build`, its core operation:\n\n`fetch/source \u2192 convert \u2192 verify`\n\nBundleCraft provides the building blocks for trust bundle creation, while your CI/CD environment orchestrates the broader workflow:\n\n`discover \u2192 build \u2192 collect \u2192 publish`\n\n**Configuration Overview:**\n\n1. **Defaults** (`config/defaults.yaml`):\n Global settings (verification, filters, formats)\n\n1. **Environments** (`config/envs/<env>.yaml`):\n Contextual overrides (paths, secrets, output formats, targets)\n\n1. **Sources** (`config/cert_sources/<source>.yaml`):\n Bundle content definition (certificate sources to include/exclude)\n - **Fetch** (`fetch:` in `<source>`): Securely fetch and stage certificates under `cert_sources/staged/<source_name>/fetch/<name>/`. Local includes are staged under `cert_sources/staged/<source_name>/<repo_name>/` (or `include/` for legacy). Staging is cleaned each run; no persistent cache.\n\n**Flow:**\n\n- Merge config layers: defaults \u2190 env \u2190 bundle\n- If `fetch:` is present, securely stage remote sources under `cert_sources/staged/<source_name>/fetch/<name>/` with provenance\n- Deduplicate, verify, and annotate certs\n- Generate canonical PEM bundle\n- Convert to supplemental formats, JKS, P7B, etc.\n- Generate `manifest.json` and `checksums.sha256`\n- Package build into `.tar.gz` tarball if configured\n- Verify all outputs and cross-format consistency\n- Optionally sign and publish release artifacts\n\n### Fetch Layer & External Integrations\n\nBundleCraft's optional **Fetch layer** enables secure retrieval of certificates from external systems, allowing you to build trust bundles from remote sources while maintaining full security and auditability.\n\n**Supported Integrations:**\n\n- **\ud83c\udf10 HTTPS URLs** - Mozilla CA bundle, public certificate repositories\n- **\ud83d\udd10 HashiCorp Vault** - Certificate storage in Vault KV stores or PKI secrets engines\n- **\ud83d\udd0c Custom APIs** - Generic REST API support with configurable authentication\n\n**Security Features:**\n\n- HTTPS-only with optional CA pinning and TLS fingerprint validation\n- Content integrity verification with SHA256 checksums\n- Full provenance tracking for compliance and audit requirements\n- Staging-only approach with no persistent caching\n\nAll fetchers support token-based authentication via environment variables and include comprehensive error handling. See [docs/fetchers.md](docs/fetchers.md) for detailed configuration examples and security best practices.\n\n______________________________________________________________________\n\n## \u26a1 Quick CLI Reference\n\nFor more detailed usage and options, see [`bundlecraft/README.md`](bundlecraft/README.md).\n\n### Core CLI\n\nAll commands work with both the Python package (`bundlecraft`) and container (`podman run ghcr.io/bundlecraft-io/bundlecraft:latest`):\n\n|Command|Purpose|Example Usage|\n|---|---|---|\n| `bundlecraft fetch` | Securely fetch remote sources and stage them (no persistent cache) | `bundlecraft fetch --env prod --bundle internal` |\n| `bundlecraft build` | Build trust bundles from configs, write all outputs | `bundlecraft build --env prod --bundle internal-prod` |\n| `bundlecraft build-all` | Discover and build all environments; supports scoping and plan output | `bundlecraft build-all --envs-path teamA --print-plan` |\n| `bundlecraft verify` | Verify PEMs or built bundle directories (expiry + integrity) | `bundlecraft verify dist/prod/internal --verify-all` |\n| `bundlecraft diff` | Compare two bundles and identify certificate changes | `bundlecraft diff --from dist/prod/v1/internal --to dist/prod/v2/internal` |\n| `bundlecraft convert` | Convert any supported input to any supported output (PEM, P7B, JKS, P12, ZIP) | `bundlecraft convert --input bundlecraft-ca-trust.pem --output-dir ./ --output-format jks` |\n\n### Common Commands\n\n#### Using Python Package\n\n```bash\n# Build all bundles in the production environment\nbundlecraft build --env prod\n\n# Build only the internal bundle in the production environment\nbundlecraft build --env prod --bundle internal\n\n# Verify a bundle\nbundlecraft verify --target dist/prod/internal --verify-all\n\n# Compare two bundles (identify certificate changes)\nbundlecraft diff --from dist/prod/v1/internal --to dist/prod/v2/internal\n\n# Convert formats\nbundlecraft convert --input bundlecraft-ca-trust.pem --output-dir ./ --output-format jks\n```\n\n#### Using Container\n\n```bash\n# Build with container (mount volumes for config, sources, and output)\npodman run --rm \\\n -v $(pwd)/config:/config \\\n -v $(pwd)/cert_sources:/cert_sources \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n build --env prod --bundle internal\n\n# Verify with container\npodman run --rm \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n verify --target /dist/prod/internal --verify-all\n\n# Convert formats with container\npodman run --rm \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n convert --input /dist/bundlecraft-ca-trust.pem --output-dir /dist --output-format jks\n```\n\n### Machine-Readable Output (JSON)\n\nAll BundleCraft commands support `--json` flag for CI/CD automation and scripting:\n\n```bash\n# Get structured output for automation\nbundlecraft build --env prod --bundle mozilla --json | jq .\n\n# Parse specific fields in scripts\nSUCCESS=$(bundlecraft fetch --source-config-file config/cert_sources/mozilla.yaml --json | jq -r '.success')\nif [ \"$SUCCESS\" = \"true\" ]; then\n echo \"Fetch succeeded\"\nfi\n\n# Extract verification results\nbundlecraft verify --target dist/prod/mozilla --json | jq -r '.verified_files'\n```\n\n- \ud83d\udcd6 **Full documentation:** [docs/JSON-OUTPUT.md](docs/JSON-OUTPUT.md)\n- \ud83d\udd0d **Examples:** [scripts/json-output-examples.sh](scripts/json-output-examples.sh)\n\n______________________________________________________________________\n\n## \u2699\ufe0f Configuration\n\n### Config Files\n\n#### Source Config (`config/cert_sources/*.yaml`)\n\nThese configuration files are your **trusted certificate sources.**\n\nIt defines where BundleCraft where retrieve CA certificates from and stage them for a build. These certificates can either come from:\n\n- `repo`: a locally committed source, useful for simplicity or if you'd like explicit control of which exact certificates are built from within the repository, along with the rest of `bundlecraft` build configuration.\n- `fetch`: a trusted remote source, such as HashiCorp Vault, Keyfactor Command, or the Mozilla CA Bundle from [curl.se](https://curl.se/docs/caextract.html). Useful when managing trusted certificates in separate systems, while still being able to use `bundlecraft` configuration to perform further filtering.\n\nThese bundles are then referenced by environment configuration files, which will go on to define which bundles these sourced certificates will appear in.\n\n```yaml\n# Optional, recommended identifiers for future controller/CRD-style tooling\napiVersion: bundlecraft.io/v1alpha1\nkind: SourceConfig\n\nbundle_name: internal\ndescription: Trust bundle for internal PKI services\nrepo:\n - name: internal\n include:\n # Path entries (string or {path: ...})\n - cert_sources/internal/rootCA.pem\n - { path: cert_sources/internal/issuingCA1.pem }\n # Inline PEM entry (optional name; if omitted, a name is generated)\n - name: special-inline.pem\n inline: |\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n\n# Optional remote sources (fetched at build time, staged with provenance)\nfetch:\n - name: mozilla_roots\n type: url\n url: https://curl.se/ca/cacert.pem\nmetadata:\n # Free-form documentation and selectors\n owner: example@bundlecraft.io\n tags: [internal]\n labels: { team: security, tier: core }\n```\n\n#### Environment Config (`config/envs/*.yaml`)\n\nDefines **how** bundles are built in a specific context, including secrets, output path, global filters, and format behavior.\n\nThese configuration files are your **customized certificate trust bundles.**\n\nIt defines how BundleCraft (based on the certificate source configurations from `config/cert_sources/`) will build, merge, package, and prepare your trust bundle files for distribution. These are essentially your environment specific configuration files.\n\nAdditional build filters, verification guardrails, packaging settings, and formatting options can be specified here.\n\n```yaml\n# Optional, recommended identifiers\napiVersion: bundlecraft.io/v1alpha1\nkind: EnvConfig\nname: Example Environment\nbuild_path: dist/example/\npackage: false\nverify:\n fail_on_expired: true\n warn_days_before_expiry: 30\noutput_formats:\n - pem\n - p7b\n - jks\n - p12\nformat_overrides:\n jks:\n storepass_env: TRUST_JKS_PASSWORD\n alias_format: \"{subject.CN}-{serial}\"\n pkcs12:\n password_env: TRUST_P12_PASSWORD\nfilters:\n unique_by_fingerprint: true\n not_expired_only: true\n ca_certs_only: true\nmetadata:\n contact: security@bundlecraft.io\n policy_version: 1.0\n```\n\nNotes on config headers and metadata\n\n- `apiVersion` and `kind` are optional but validated when present. They future\u2011proof configs for strict environments (e.g., Kubernetes-style controllers) without changing behavior.\n- `metadata.labels` is supported on source and environment configs to attach machine-readable key/value tags for internal automation. It\u2019s not used for selection today (envs reference sources by name only) but provides a clean place for future selectors and CI policies.\n- Separation of concerns is enforced: environment configs compose sources by name and control build/distribution; source configs own repo/fetch definitions. Envs do not reference nested repo/fetch entries.\n\n#### Defaults (`config/defaults.yaml`)\n\nBaseline settings for verification, filters, output formats, and metadata.\nThese can be overridden by environment or source configs.\n\n### Environment Variables\n\nBundleCraft supports the following environment variables for configuration:\n\n| Variable | Purpose | Default Value | Used By |\n|------------------------|-----------------------------------------------|----------------|------------------|\n| `TRUST_JKS_PASSWORD` | Password for Java KeyStore operations | `\"changeit\"` | Convert, Verify |\n| `TRUST_P12_PASSWORD` | Password for PKCS#12 operations | `\"changeit\"` | Convert, Verify |\n| `BUNDLECRAFT_WORKSPACE` | Override workspace directory for builds | Current directory | Builder |\n| `VAULT_TOKEN` | HashiCorp Vault authentication token | - | Vault Fetcher |\n| `VAULT_ADDR` | HashiCorp Vault server address | - | Vault Fetcher |\n| `KEYFACTOR_TOKEN` | Keyfactor API authentication token | - | API Fetcher |\n| `GPG_KEY_ID` | GPG key identifier for signing operations | - | Signing |\n| `GPG_PASSPHRASE` | GPG key passphrase for signing | `\"\"` (empty) | Signing |\n\n**Note:**\n\n- Password variables are used as fallback values and can be overridden via CLI options or config files\n- Authentication tokens (`*_TOKEN`) are required when using their respective fetchers\n- Signing variables are only needed when using `--sign` option\n- Workspace variable is primarily used for development and testing environments\n\n______________________________________________________________________\n\n## \ud83d\udd10 Security & Verification\n\n- **Strict Expiry Handling:** Build fails if any cert is expired (unless configured otherwise)\n- **Deduplication:** SHA256 fingerprint used for unique certs\n- **Subject Annotation:** PEM includes `# Subject:` comments for traceability\n- **Manifest & Checksums:** Every build records outputs with SHA256 in both JSON and text formats\n- **Cross-format Verification:** Cert counts and file integrity checked for PEM, P7B, JKS, P12\n- **Fetch provenance:** `provenance.fetch.json` recorded in staging and embedded into `manifest.json` under `fetched`\n- **Network trust controls:** HTTPS only (for APIs and URLs), optional custom CA, optional TLS leaf fingerprint pinning, and optional content `sha256` pinning\n- **GPG signing:** Sign all release artifacts with detached GPG signatures (.asc files)\n- **SBOM generation:** Automatic Software Bill of Materials in CycloneDX format\n- **Signature verification:** Built-in verification for signed releases with keyring support\n- **Dependency lock file:** Production builds use exact dependency versions from `requirements-lock.txt` for reproducibility (see [CONTRIBUTING.md](./CONTRIBUTING.md#dependency-lock-file))\n\nFor more, see: [`SECURITY.md`](./SECURITY.md)\n\n______________________________________________________________________\n\n## \u270d\ud83c\udffd Signing Release Artifacts\n\nOptionally, sign all release artifacts with GPG during your build for verification later on:\n\n```bash\n# Generate or use existing GPG key\ngpg --full-generate-key\n\n# Build and sign artifacts\nexport GPG_KEY_ID=ABCD1234EFGH5678\nbundlecraft build --env prod --bundle mozilla --sign\n\n# Verify signatures\nbundlecraft verify --target dist/Production/mozilla --verify-signatures\n```\n\nSee [SIGNING-AND-SBOM.md](docs/SIGNING-AND-SBOM.md) for the complete guide on:\n\n- GPG key generation and management\n- CI/CD integration with GitHub Actions\n- SBOM usage and validation\n- Key management best practices\n\n______________________________________________________________________\n\n## \ud83e\udded Troubleshooting & FAQ\n\n### Container Issues\n\n**Container volume mount issues?**\nEnsure volumes are mounted correctly:\n\n```bash\npodman run --rm \\\n -v $(pwd)/config:/config \\\n -v $(pwd)/cert_sources:/cert_sources \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n build --env prod\n```\n\n- **Verifier says JKS=0?**\n Ensure password is correct. The default password is `\"changeit\"`. Set `TRUST_JKS_PASSWORD` env var if using a different password.\n\n```bash\npodman run --user $(id -u):$(id -g) --rm \\\n -v $(pwd)/config:/config \\\n -v $(pwd)/cert_sources:/cert_sources \\\n -v $(pwd)/dist:/dist \\\n ghcr.io/bundlecraft-io/bundlecraft:latest \\\n build --env prod\n```\n\n### Format & Conversion Issues\n\n**Empty P7B files?**\nEnsure your PEM input files contain valid certificates. BundleCraft uses the Python `cryptography` module for all format conversions.\n\n**P12 only contains one certificate?**\nThis has been fixed in the current version - all certificates from the bundle are included in the PKCS#12 output.\n\n**Duplicate JKS aliases?**\nThe build process removes existing keystores before import to prevent conflicts. Ensure you're using the latest version.\n\n### Authentication & Secrets\n\n**Password issues with keystores?**\nDefault passwords are `\"changeit\"` for both JKS and P12 formats. Override with environment variables:\n\n```bash\nexport TRUST_JKS_PASSWORD=\"your-jks-password\" #pragma: allowlist secret\nexport TRUST_P12_PASSWORD=\"your-p12-password\" #pragma: allowlist secret\nbundlecraft build --env prod\n```\n\n**Vault authentication failing?**\nEnsure both `VAULT_TOKEN` and `VAULT_ADDR` are set:\n\n```bash\nexport VAULT_TOKEN=\"hvs.your-vault-token\"\nexport VAULT_ADDR=\"https://vault.example.com:8200\"\n```\n\n**Keyfactor API authentication issues?**\nSet the `KEYFACTOR_TOKEN` environment variable:\n\n```bash\nexport KEYFACTOR_TOKEN=\"your-keyfactor-api-token\"\n```\n\n### Network & Fetch Issues\n\n**\"Insecure HTTP rejected\" errors?**\nBundleCraft only supports HTTPS for security. Use `https://` URLs or `file://` for local files. For APIs, configure proper CA verification:\n\n```yaml\nfetch:\n - name: secure_source\n type: api\n endpoint: https://api.example.com/certificates\n verify:\n ca_file: config/certs/api-ca.pem\n tls_fingerprint_sha256: \"abc123...\" # optional\n```\n\n**SHA256 content mismatch errors?**\nUpdate the expected `verify.sha256` value to match the current content, or investigate if the source has changed unexpectedly:\n\n```yaml\nverify:\n sha256: \"new-expected-sha256-hash\"\n```\n\n**TLS fingerprint mismatch errors?**\nRe-check the server certificate fingerprint (leaf certificate). If it rotated legitimately, update the configuration:\n\n```yaml\nverify:\n tls_fingerprint_sha256: \"new-leaf-certificate-fingerprint\"\n```\n\nWhen using containers, Vault support is included by default.\n\n### Build & Configuration Issues\n\n**Offline builds needed?**\nUse `bundlecraft build --skip-fetch` to avoid network access. If your config includes `fetch:` sections, pre-stage certificates:\n\n```bash\n# In connected environment\nbundlecraft fetch --env prod\n\n# Commit or package staged inputs\n# Then in offline environment\nbundlecraft build --env prod --skip-fetch\n```\n\n**Configuration validation errors?**\nCheck YAML syntax and ensure all required fields are present. Use the `--verbose` flag for detailed error information:\n\n```bash\nbundlecraft build --env prod --verbose\n```\n\n**Certificate expiry warnings or failures?**\nConfigure expiry handling in your environment config:\n\n```yaml\nverify:\n fail_on_expired: false # Don't fail builds on expired certs\n warn_days_before_expiry: 30 # Warn 30 days before expiry\n```\n\n### Common Commands for Debugging\n\n```bash\n# Verbose output for detailed error information\nbundlecraft build --env prod --verbose\n\n# JSON output for structured error parsing\nbundlecraft build --env prod --json\n\n# Verify a specific bundle with detailed output\nbundlecraft verify --target dist/prod/internal --verify-all --verbose\n\n# Test fetch configuration without building\nbundlecraft fetch --env prod --bundle internal --verbose\n```\n\n### Additional Resources\n\nFor more detailed troubleshooting information, see:\n\n- \ud83d\udcd6 [Complete Troubleshooting Guide](docs/troubleshooting.md)\n- \ud83d\udd27 [Configuration Specification](docs/CONFIG-SPEC.md)\n- \ud83d\udeab [Anti-Patterns Guide](docs/ANTI-PATTERNS.md)\n- \ud83d\udcac [GitHub Discussions](https://github.com/bundlecraft-io/bundlecraft/discussions) for community support\n\n______________________________________________________________________\n\n## \ud83d\udd2e Philosophy & Best Practices\n\n### Philosophy\n\nBundleCraft treats certificate trust management as a holistic engineering problem requiring reproducibility, auditability, and security at every layer. Rather than just being another certificate conversion tool, BundleCraft provides a complete configuration-as-code approach to trust store management.\n\n**Core Design Principles:**\n\n- **Declarative configuration:** Define what you want, not how to get it - BundleCraft handles the complexity\n- **Reproducible builds:** Same inputs always produce identical outputs across environments and time\n- **Defense in depth:** Multiple verification layers from source validation to output integrity checking\n- **Full provenance:** Every operation is tracked and auditable for compliance and debugging\n- **Environment awareness:** Support different trust requirements across dev, staging, and production\n- **Format agnostic:** Universal trust bundle that works across all platforms and technologies\n\n### Best Practices\n\n**Security:**\n\n- Always use HTTPS; never `http://`\n- Pin content (`verify.sha256`) for static/public bundles when possible (e.g., Mozilla)\n- For APIs/services, prefer TLS CA pinning and optionally leaf fingerprint pinning\n- Keep tokens in env vars (`*_TOKEN`) and never commit secrets in YAML\n\n**Configuration Management:**\n\n- Commit sample configs but not secrets; use CI secret stores for tokens\n- Treat `cert_sources/staged/` as ephemeral; do not rely on it as a cache\n- Use layered configs: defaults \u2192 environment \u2192 bundle for clean separation\n- Test configurations in non-production environments first\n\n**Operational:**\n\n- Use `--json` output for CI/CD automation and monitoring\n- Implement certificate expiry monitoring with configurable thresholds\n- Regularly verify bundle integrity across all environments\n- Document your certificate sources and approval processes\n\n______________________________________________________________________\n\n## \ud83d\udcdd Additional Documentation\n\nFor topics not discussed in this README, or for topics that need their own page.\n\n**See: [`docs/README.md`](docs/README.md)**\n\n______________________________________________________________________\n\n## \ud83e\udd1d Contributing\n\n- Issues and PRs are welcome!\n- Check out [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) before getting started for come community guidelines.\n- See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to interact with the codebase and release process.\n\n______________________________________________________________________\n\n## \ud83d\udccb Changelog\n\nSee [CHANGELOG.md](https://github.com/bundlecraft-io/bundlecraft/blob/main/CHANGELOG.md) for release history and what's changed between versions.\n\n______________________________________________________________________\n\n## \ud83c\udff7\ufe0f Tags & Metadata\n\n- **Topics:** python, tls, cli, security, cryptography, openssl, certificates, x509, pki, keystore, pem, cicd, bundles, devsecops, truststore, ca-certificates, certificate-management, pki-tools\n\n______________________________________________________________________\n\n## \ud83d\udd17 Related Projects & References\n\n**BundleCraft Ecosystem:**\n\n- [\ud83e\uddf1 BundleCraft Starter](https://github.com/bundlecraft-io/bundlecraft-starter) - Template repository with GitHub Actions workflow for orchestrating your own BundleCraft builds.\n- [\ud83e\uddd1\ud83c\udffd\u200d\ud83d\udcbb BundleCraft Demo](https://github.com/bundlecraft-io/bundlecraft-demo) - Mock environment for showcasing BundleCraft's usages and potential applications in the format of sample scenario.\n\n**Standards & Documentation:**\n\n- [RFC 5280 - Internet X.509 PKI Certificate and CRL Profile](https://datatracker.ietf.org/doc/html/rfc5280)\n- [RFC 5652 - Cryptographic Message Syntax (CMS / PKCS#7)](https://datatracker.ietf.org/doc/html/rfc5652)\n- [RFC 7292 - PKCS #12 v1.1 (Personal Information Exchange)](https://datatracker.ietf.org/doc/html/rfc7292)\n- [Python cryptography library documentation](https://cryptography.io/)\n\n______________________________________________________________________\n\n## \ud83d\ude4f Acknowledgements\n\nCertificates are easy. Certificate management is hard.\n\nSpecial thanks to all the security and infrastructure teams out there, whose collective experience and guidance has fueled this project.\n\n______________________________________________________________________\n\n## \ud83d\udce3 Questions?\n\nOpen an [issue](https://github.com/bundlecraft-io/bundlecraft/issues)\nor reach out via [GitHub Discussions](https://github.com/bundlecraft-io/bundlecraft/discussions)\n\n______________________________________________________________________\n\n\u00a9 2025 BundleCraft.io\nLicensed under the [MIT License](./LICENSE).\n\n> Made with \u2764\ufe0f (and \u2615) for anyone who\u2019s ever debugged a broken trust chain.\n> BundleCraft is a passion project, built to make certificate trust a little less painful for everyone.\n> Contributions, ideas, and curiosity are always welcome.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Modern tool for building and managing CA trust bundles across multiple formats and environments",
"version": "0.3.0",
"project_urls": {
"Changelog": "https://github.com/bundlecraft-io/bundlecraft/releases/tag/v0.3.0",
"Documentation": "https://github.com/bundlecraft-io/bundlecraft#readme",
"Homepage": "https://github.com/bundlecraft-io/bundlecraft",
"Issues": "https://github.com/bundlecraft-io/bundlecraft/issues",
"Repository": "https://github.com/bundlecraft-io/bundlecraft"
},
"split_keywords": [
"ca-bundle",
" certificates",
" cryptography",
" pki",
" security",
" trust-store"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "02191b4a0146006e1763114e61d887ceac56662578b193b30270faea4a99b5a2",
"md5": "37ddd124de003e4c0d705b89537c2a9d",
"sha256": "4b26cec9461ce128ca4dd9fd59c8cbc290188cff56ad8440134c4d6f3b5b4900"
},
"downloads": -1,
"filename": "bundlecraft-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "37ddd124de003e4c0d705b89537c2a9d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 108608,
"upload_time": "2025-11-08T22:54:44",
"upload_time_iso_8601": "2025-11-08T22:54:44.337870Z",
"url": "https://files.pythonhosted.org/packages/02/19/1b4a0146006e1763114e61d887ceac56662578b193b30270faea4a99b5a2/bundlecraft-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "7a608ebc515d496c4172b56df45bd118ea72c5e42da2900e07ab72e94d8eb2d9",
"md5": "e1d2906b29a14bd8679a47814f443a52",
"sha256": "85b2bfd5bec54ae94a2d6cad21a8e1bfeed91b194a654807a71b1ce929003d66"
},
"downloads": -1,
"filename": "bundlecraft-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "e1d2906b29a14bd8679a47814f443a52",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 101718,
"upload_time": "2025-11-08T22:54:45",
"upload_time_iso_8601": "2025-11-08T22:54:45.949162Z",
"url": "https://files.pythonhosted.org/packages/7a/60/8ebc515d496c4172b56df45bd118ea72c5e42da2900e07ab72e94d8eb2d9/bundlecraft-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-08 22:54:45",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bundlecraft-io",
"github_project": "bundlecraft",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "bundlecraft"
}