https://github.com/zcloud-ws/secure-templates
Secure Templates is a tool to render templates using go-templates and load data values from secrets engine.
https://github.com/zcloud-ws/secure-templates
secret secrets security security-tools template templates
Last synced: 4 months ago
JSON representation
Secure Templates is a tool to render templates using go-templates and load data values from secrets engine.
- Host: GitHub
- URL: https://github.com/zcloud-ws/secure-templates
- Owner: zcloud-ws
- License: mit
- Created: 2024-02-10T02:09:39.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2026-02-24T13:59:46.000Z (4 months ago)
- Last Synced: 2026-02-24T18:50:37.072Z (4 months ago)
- Topics: secret, secrets, security, security-tools, template, templates
- Language: Go
- Homepage:
- Size: 270 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# Secure Templates
[](coverage/cover.html)
A CLI tool that renders [Go templates](https://pkg.go.dev/text/template) with secret values loaded from pluggable secret engines. Keep your templates in version control and inject secrets at render time.
**Binary:** `secure-templates` (alias: `stpl`)
## Features
- Render any text file using Go template syntax with secret injection
- Pluggable secret engines: HashiCorp Vault, OCI Vault, local encrypted file, or no-op
- Built-in [sprig](https://masterminds.github.io/sprig/) template functions (100+ utility functions)
- Custom template delimiters to avoid conflicts with Helm, Jinja, etc.
- Environment variable support in templates and config values
- Secret introspection with `--print-keys`
## Installation
### Linux and macOS
Install the latest version (auto-detects OS and architecture):
```shell
curl -sL https://raw.githubusercontent.com/zcloud-ws/secure-templates/main/scripts/install.sh | bash
```
The installer will place the binary in `/usr/local/bin` if writable, or `~/.local/bin` as fallback. It also creates an `stpl` alias. Use `sudo` if you need to install to a system directory:
```shell
curl -sL https://raw.githubusercontent.com/zcloud-ws/secure-templates/main/scripts/install.sh | sudo bash
```
**Customize with environment variables:**
| Variable | Description |
|----------|-------------|
| `STPL_VERSION` | Install a specific version (e.g., `0.1.0` or `v0.1.0`) |
| `STPL_INSTALL_DIR` | Custom installation directory |
| `STPL_ALIAS_NAME` | Custom alias name (default: `stpl`, set empty to skip) |
```shell
# Install a specific version to a custom directory
STPL_VERSION=0.1.0 STPL_INSTALL_DIR=/opt/bin curl -sL https://raw.githubusercontent.com/zcloud-ws/secure-templates/main/scripts/install.sh | bash
```
### Manual / Windows
Download the binary for your platform from the [releases page](https://github.com/zcloud-ws/secure-templates/releases).
## Quick Start
```shell
# 1. Generate a config with local-file secret engine
secure-templates init-config -o config.json
# 2. Store a secret
secure-templates -c config.json manage-secret put myapp db_password "s3cr3t"
# 3. Create a template
echo 'DB_PASSWORD={{ secret "myapp" "db_password" }}' > app.env.tpl
# 4. Render
secure-templates -c config.json app.env.tpl
# Output: DB_PASSWORD=s3cr3t
```
## Template Functions
### `secret`
Retrieves a value from the configured secret engine.
```
{{ secret "secret_name" "key_name" }}
```
When called with only the secret name, returns a key-value map that can be iterated:
```
{{ range $key, $value := secret "secret_name" -}}
{{ $key }}={{ $value }}
{{ end }}
```
### `env`
Reads an environment variable:
```
{{ env "MY_VAR" }}
```
### Sprig functions
All [sprig](https://masterminds.github.io/sprig/) functions are available. Common examples:
```
{{ secret "app" "password" | b64enc }} # base64 encode
{{ env "HOST" | upper }} # uppercase
{{ secret "app" "name" | default "myapp" }} # default value
```
## Commands
### `init-config`
Generate a sample config file with the `local-file` secret engine:
```shell
secure-templates init-config -o config.json
```
| Flag | Env var | Description |
|------|---------|-------------|
| `--output`, `-o` | `SEC_TPL_OUTPUT` | Output file path (stdout if omitted) |
| `--secret-file` | | Path for the secret data file |
| `--private-key-passphrase` | `LOCAL_SECRET_PRIVATE_KEY_PASSPHRASE` | Passphrase for RSA key encryption |
### `manage-secret`
Manage secrets in the configured engine.
**Add or update a single key:**
```shell
secure-templates -c config.json manage-secret put
```
**Import keys from an .env file:**
```shell
secure-templates -c config.json manage-secret import
```
### Render (default action)
Render a template file using values from the configured secret engine:
```shell
secure-templates -c config.json [flags]
```
| Flag | Env var | Description |
|------|---------|-------------|
| `--config`, `-c` | `SEC_TPL_CONFIG` | Path to config file |
| `--output`, `-o` | `SEC_TPL_OUTPUT` | Output file (stdout if omitted) |
| `--print-keys`, `-p` | | List secret key references used in the template |
| `--left-delim`, `--ld` | `SEC_TPL_LEFT_DELIM` | Custom left template delimiter |
| `--right-delim`, `--rd` | `SEC_TPL_RIGHT_DELIM` | Custom right template delimiter |
## Custom Template Delimiters
When rendering templates that target systems using Go template syntax (e.g., Helm charts), the default `{{ }}` delimiters conflict. Use custom delimiters so that `secure-templates` only processes its own expressions while standard `{{ }}` passes through untouched.
**Example** - a Helm values file using `<< >>` delimiters:
Template (`values.yaml.tpl`):
```yaml
app_user: {{ .Values.appUser }}
app_password: << secret "core" "app_passwd" >>
```
Render:
```shell
secure-templates --left-delim "<<" --right-delim ">>" values.yaml.tpl
```
Output:
```yaml
app_user: {{ .Values.appUser }}
app_password: s3cr3t_v4lu3
```
Custom delimiters can also be set in the config file:
```json
{
"options": {
"leftDelim": "<<",
"rightDelim": ">>"
}
}
```
CLI flags take precedence over config file values.
## Supported Secret Engines
### HashiCorp Vault
Uses the [Vault KVv2](https://www.vaultproject.io/) secret engine.
| Env var | Description |
|---------|-------------|
| `VAULT_ADDR` | Vault server address |
| `VAULT_TOKEN` | Authentication token |
| `VAULT_SECRET_ENGINE` | Secret engine name |
| `VAULT_NS` | Vault namespace |
For local development, a Docker Compose setup is available in [`dev/vault/`](dev/vault/README.md).
### OCI Vault
Uses [Oracle Cloud Infrastructure Vault](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Concepts/keyoverview.htm) as the secret engine. Each OCI secret stores a single value (native key-value model).
In templates, the first parameter is the **vault name** and the second is the **secret name**:
```
{{ secret "my-vault" "db_password" }}
```
This allows accessing secrets from multiple vaults in a single template. The vault is resolved by display name within the configured compartment.
For single-arg calls (`{{ secret "db_password" }}`), the default vault OCID from config/env is used.
| Env var | Description |
|---------|-------------|
| `OCI_CONFIG_FILE` | Path to OCI config file (default: `~/.oci/config`) |
| `OCI_CONFIG_PROFILE` | OCI config profile (default: `DEFAULT`) |
| `OCI_VAULT_OCID` | Default OCI Vault OCID (optional, used for single-arg secret calls) |
| `OCI_COMPARTMENT_OCID` | OCI Compartment OCID (required for vault name resolution and write operations) |
| `OCI_KEY_OCID` | OCI Master Encryption Key OCID (required for write operations) |
### Local File
Stores secrets in a local JSON file encrypted with RSA (OAEP + SHA256).
| Env var | Description |
|---------|-------------|
| `LOCAL_SECRET_PRIVATE_KEY` | Base64-encoded RSA private key |
| `LOCAL_SECRET_PRIVATE_KEY_PASSPHRASE` | Passphrase for the RSA key |
## Config File
```json
{
"secret_engine": "local-file",
"vault_config": {
"address": "http://localhost:8200",
"token": "token",
"secret_engine": "kv",
"ns": "dev"
},
"local_file_config": {
"filename": "secrets.json",
"enc_priv_key": "LS0tLS...."
},
"oci_vault_config": {
"vault_ocid": "$OCI_VAULT_OCID",
"compartment_ocid": "$OCI_COMPARTMENT_OCID",
"key_ocid": "$OCI_KEY_OCID"
},
"options": {
"secretShowNameAsValueIfEmpty": false,
"secretIgnoreNotFoundKey": false,
"envShowNameAsValueIfEmpty": false,
"envAllowAccessToSecureTemplateEnvs": false,
"envRestrictedNameRegex": "SC_.+",
"leftDelim": "",
"rightDelim": ""
}
}
```
Config values support environment variable expansion: any value containing `$` is expanded (e.g., `"$VAULT_TOKEN"`).
### Options Reference
| Option | Default | Description |
|--------|---------|-------------|
| `secretShowNameAsValueIfEmpty` | `false` | Show the key name as value when the secret value is empty |
| `secretIgnoreNotFoundKey` | `false` | Ignore missing keys instead of failing |
| `envShowNameAsValueIfEmpty` | `false` | Show the variable name as value when the env var is empty |
| `envAllowAccessToSecureTemplateEnvs` | `false` | Allow `env` function to access `secure-templates` internal env vars |
| `envRestrictedNameRegex` | `""` | Regex pattern for restricted env var names (e.g., `SC_.+`) |
| `leftDelim` | `""` | Custom left template delimiter (empty = `{{`) |
| `rightDelim` | `""` | Custom right template delimiter (empty = `}}`) |
## Examples
### .env file
Template ([source](./test/samples/.env)):
```
export APP_USER={{ secret "core" "app_user" }}
export APP_PASSWORD={{ secret "core" "app_passwd" }}
```
Output:
```
export APP_USER=dev_user
export APP_PASSWORD=2dabe3d7c66fb75f751202fdab19266b
```
### Kubernetes Secret
Template ([source](./test/samples/k8s-secret.yaml)):
```yaml
apiVersion: v1
kind: Secret
metadata:
name: {{ env "SECRET_NAME" }}
namespace: {{ env "SECRET_NAMESPACE" }}
data:
APP_USER: {{ secret "core" "app_user" | b64enc }}
APP_PASSWORD: {{ secret "core" "app_passwd" | b64enc }}
stringData:
CLIENT_APP_USER: "{{ secret "client" "app_user" }}"
CLIENT_APP_PASSWORD: "{{ secret "client" "app_passwd" }}"
```
### Iterating over secret keys
Template ([source](./test/samples/secrets-list.env)):
```
{{ range $key, $value := secret "test" -}}
{{ $key }}:{{ $value }}
{{ end }}
```
## Building from Source
```bash
# Build
go build -o secure-templates .
# Run tests
cd test && go test ./...
# Coverage report
./coverage-update.sh
```
Requires Go 1.21+.
## Author
Edimar Cardoso
- [edimarlnx@gmail.com](mailto:edimarlnx@gmail.com)
- [edimar@quave.one](mailto:edimar@quave.one)
- [oss@quave.one](mailto:oss@quave.one)
- Website: [www.quave.one](https://www.quave.one)
## License
[MIT](./LICENSE)