A Rust implementation of envato/ejsonkms. This is a drop-in replacement for the original Go implementation, with support for YAML and TOML file formats.
ejsonkms uses the ejson-rs library with AWS Key Management Service to simplify deployments on AWS. The EJSON private key is encrypted with KMS and stored inside the EJSON file as _private_key_enc. Access to decrypt secrets can be controlled with IAM permissions on the KMS key.
| Format | Extensions | Status |
|---|---|---|
| JSON | .ejson, .json |
Supported |
| YAML | .eyaml, .eyml, .yaml, .yml |
Supported |
| TOML | .etoml, .toml |
Supported |
The file format is automatically detected based on the file extension.
Download compiled binaries from Releases.
git clone https://github.com/runlevel5/ejsonkms-rs.git
cd ejson-rs
cargo build --release
cp ./target/release/ejsonkms ~/.local/bin/$ ejsonkms keygen --aws-region us-east-1 --kms-key-id bc436485-5092-42b8-92a3-0aa8b93536dc -o secrets.ejson
$ cat secrets.ejson
{
"_public_key": "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52",
"_private_key_enc": "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAAycRX5OBx6xGuYOPAmDJ1FombB1lFybMP42s7PGmoa24bAesPMMZtI9V0w0p0lEgLeeSvYdsPuoPROa4bwnQxJB28eC6fHgfWgY7jgDWY9uP/tgzuWL3zuIaq+9Q=="
}Security Note: The raw private key is never printed to the console. The private key is encrypted with KMS and stored as
_private_key_encin the output file.
To generate a YAML file instead, use a .eyaml or .eyml extension:
$ ejsonkms keygen --aws-region us-east-1 --kms-key-id bc436485-5092-42b8-92a3-0aa8b93536dc -o secrets.eyaml
$ cat secrets.eyaml
_public_key: 6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52
_private_key_enc: S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAAycRX5OBx6xGuYOPAmDJ1FombB1lFybMP42s7PGmoa24bAesPMMZtI9V0w0p0lEgLeeSvYdsPuoPROa4bwnQxJB28eC6fHgfWgY7jgDWY9uP/tgzuWL3zuIaq+9Q==$ ejsonkms encrypt secrets.ejsonAdding secrets and non-secrets to the environment attribute:
The environment attribute is where you store your configuration values. There are two types of values:
- Secrets - Keys without an underscore prefix will be encrypted when you run
ejsonkms encrypt - Non-secrets - Keys prefixed with
_(underscore) will remain in plaintext and won't be encrypted
# Edit your secrets.ejson file and add values to the environment attribute:
$ cat secrets.ejson
{
"_public_key": "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52",
"_private_key_enc": "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAAycRX5OBx6xGuYOPAmDJ1FombB1lFybMP42s7PGmoa24bAesPMMZtI9V0w0p0lEgLeeSvYdsPuoPROa4bwnQxJB28eC6fHgfWgY7jgDWY9uP/tgzuWL3zuIaq+9Q==",
"secret_1": "supersecretpassword",
"_non_secret_1": "cleartext",
"environment": {
"DATABASE_PASSWORD": "supersecretpassword",
"API_KEY": "sk-1234567890abcdef",
"JWT_SECRET": "my-jwt-signing-key",
"_DATABASE_HOST": "db.example.com",
"_DATABASE_PORT": "5432",
"_APP_ENV": "production"
}
}After running ejsonkms encrypt secrets.ejson, the file will look like:
{
"_public_key": "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52",
"_private_key_enc": "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAAycRX5OBx6xGuYOPAmDJ1FombB1lFybMP42s7PGmoa24bAesPMMZtI9V0w0p0lEgLeeSvYdsPuoPROa4bwnQxJB28eC6fHgfWgY7jgDWY9uP/tgzuWL3zuIaq+9Q==",
"secret_1": "EJ[1:ZH5kC...encrypted...]:...",
"_non_secret_1": "cleartext",
"environment": {
"DATABASE_PASSWORD": "EJ[1:ZH5kC...encrypted...]:...",
"API_KEY": "EJ[1:AB3xY...encrypted...]:...",
"JWT_SECRET": "EJ[1:CD7zW...encrypted...]:...",
"_DATABASE_HOST": "db.example.com",
"_DATABASE_PORT": "5432",
"_APP_ENV": "production"
}
}Notice that:
DATABASE_PASSWORD,API_KEY, andJWT_SECRETare now encrypted (values starting withEJ[...)_DATABASE_HOST,_DATABASE_PORT, and_APP_ENVremain in plaintext because they have the_prefix
$ ejsonkms decrypt secrets.ejson
{
"_public_key": "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52",
"_private_key_enc": "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAAycRX5OBx6xGuYOPAmDJ1FombB1lFybMP42s7PGmoa24bAesPMMZtI9V0w0p0lEgLeeSvYdsPuoPROa4bwnQxJB28eC6fHgfWgY7jgDWY9uP/tgzuWL3zuIaq+9Q==",
"secret_1": "supersecretpassword",
"non_secret_1": "cleartext",
"environment": {
"DATABASE_PASSWORD": "supersecretpassword",
"API_KEY": "sk-1234567890abcdef",
"JWT_SECRET": "my-jwt-signing-key",
"DATABASE_HOST": "db.example.com",
"DATABASE_PORT": "5432",
"APP_ENV": "production"
}
}Note that the leading underscore is automatically stripped from keys during decryption. For example, _non_secret_1 becomes non_secret_1, and _DATABASE_HOST becomes DATABASE_HOST. Keys with multiple underscores (e.g., __KEY) will have only the first underscore removed (becoming _KEY).
$ exports=$(ejsonkms env secrets.ejson)
$ echo $exports
export DATABASE_PASSWORD='supersecretpassword'
export API_KEY='sk-1234567890abcdef'
export JWT_SECRET='my-jwt-signing-key'
export DATABASE_HOST='db.example.com'
export DATABASE_PORT='5432'
export APP_ENV='production'
$ eval $exports
$ echo $DATABASE_PASSWORD
supersecretpasswordNote that only values under the environment key will be exported using the env command.
The same secrets can be stored in YAML format:
# secrets.eyaml
_public_key: 6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52
_private_key_enc: S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAA...
environment:
DATABASE_PASSWORD: supersecretpassword
API_KEY: sk-1234567890abcdef
JWT_SECRET: my-jwt-signing-key
_DATABASE_HOST: db.example.com
_DATABASE_PORT: "5432"
_APP_ENV: productionAll commands work the same way with YAML files:
$ ejsonkms encrypt secrets.eyaml
$ ejsonkms decrypt secrets.eyaml
$ ejsonkms env secrets.eyamlTo generate a ETOML file, use a .etoml or .toml extension:
$ ejsonkms keygen --aws-region us-east-1 --kms-key-id bc436485-5092-42b8-92a3-0aa8b93536dc -o secrets.etoml
$ cat secrets.etoml
_public_key = "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52"
_private_key_enc = "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAA..."The same secrets can be stored in TOML format:
# secrets.etoml
_public_key = "6b8280f86aff5f48773f63d60e655e2f3dd0dd7c14f5fecb5df22936e5a3be52"
_private_key_enc = "S2Fybjphd3M6a21zOnVzLWVhc3QtMToxMTExMjIyMjMzMzM6a2V5L2JjNDM2NDg1LTUwOTItNDJiOC05MmEzLTBhYThiOTM1MzZkYwAAAAA..."
[environment]
DATABASE_PASSWORD = "supersecretpassword"
API_KEY = "sk-1234567890abcdef"
JWT_SECRET = "my-jwt-signing-key"
_DATABASE_HOST = "db.example.com"
_DATABASE_PORT = "5432"
_APP_ENV = "production"All commands work the same way with TOML files:
$ ejsonkms encrypt secrets.etoml
$ ejsonkms decrypt secrets.etoml
$ ejsonkms env secrets.etomlA pre-commit hook is also supported to automatically run ejsonkms encrypt on all .ejson, .eyaml, .eyml, .etoml, and .toml files in a repository.
To use, add the following to a .pre-commit-config.yaml file in your repository:
repos:
- repo: https://github.com/runlevel5/ejsonkms-rs
hooks:
- id: run-ejsonkms-encrypt