Jets Env SSM Parameter Store Support

AWS Systems Manager Parameter Store is supported. Jets dotenv files support referencing SSM Parameter Store values. This behavior only applies to Jets config/jets/env files.

Autoload Convention Path

Jets will autoload SSM parameters under the path of /PROJECT/ENV/. This means SSM parameters like

/demo/dev/DATABASE_URL
/demo/dev/SECRET_KEY_BASE

All you have to do is create them in AWS SSM parameter store, and they are automatically loaded. So the config/jets/env/.env is entirely optional. This behavior can be configured with:

config/jets/project.rb

Jets.project.configure do
  config.dotenv.ssm.autoload = true # default: true
end

This spares you from updating your config/jets/env files with newly added SSM parameters. Here’s a useful CLI command to see what values are in SSM.

❯ aws ssm get-parameters-by-path --path "/demo/dev/" | jq -r '.Parameters[].Name' | sort
/demo/dev/DATABASE_URL
/demo/dev/SECRET_KEY_BASE

For those who prefer more control over the SSM env variables, you can turn off the behavior and use explicit jets/config/env files. If you using both, the explicit values always win.

Note: Jets uses the optimized get_parameters_by_path API call. It efficiently retrieves multiple parameters that share a path hierarchy. This minimizes API calls compared to fetching parameters individually and avoids rate limit issues. The implementation does not use the recursive option by design, so the parameters should be within the same hierarchy level.

Explicit SSM Usage in Env Files

Storing secrets as SSM Parameters and referencing them your .env files allows you to commit your .env into source control. When you reference a parameter name with it will prefix the conventional /PROJECT/ENV/. If you reference the parameter name with a leading / then the conventional prefix is not added. For example:

RELATIVE_DATABASE_URL=SSM:database-url          # references /PROJECT/ENV/database-url
ABSOLUTE_DATABASE_URL=SSM:/path/to/database-url # references /path/to/database-url

The SSM parameters are fetched and interpolated into your environment at build time. After changing your SSM parameters, make sure to re-deploy your app to ensure they are picked up correctly.

Config

To customize the conventional behavior, you can use.

config/jets/project.rb

Jets.project.configure do
  config.dotenv.ssm.one_dev = true
  config.dotenv.ssm.convention_resolver = ->(ssm_leaf_name) do
    "/#{Jets.project.name}/#{ssm_env}/#{ssm_leaf_name}"
  end
end

Tip: Use jets dotenv:list to quickly test changes.

SSM Helper: ssm_env

The ssm_env helper resolves to an env value that is smarter than Jets.env.

For JETS_ENV=dev and JETS_ENV=prod, ssm_env returns the corresponding JETS_ENV. For other values, ssm_env returns dev. This is because users often want additional dev-like environments but do not want to have to recreate all the SSM secrets for each environment. This allows the SSM params to be DRY. Here are some examples to explain:

JETS_ENV=dev  # ssm_env => dev
JETS_ENV=prod # ssm_env => prod
JETS_ENV=qa   # ssm_env => dev   # config.dotenv.ssm.one_dev = true

This behavior can be changed with config.dotenv.ssm.one_dev = false. In that case, JETS_ENV is passed through.

JETS_ENV=dev  # ssm_env => dev
JETS_ENV=prod # ssm_env => prod
JETS_ENV=qa   # ssm_env => qa   # config.dotenv.ssm.one_dev = false

Shared SSM Parameters Example

The ssm_env helper is also useful for shared env values. Here’s an example:

config/jets/bootstrap.rb

Jets.bootstrap.configure do
  config.codebuild.project.env.vars = {
    BUNDLE_GITHUB__COM: "SSM:/#{ssm_env}/BUNDLE_GITHUB__COM",
    DOCKER_PASS: "SSM:/#{ssm_env}/DOCKER_PASS",
    DOCKER_USER: "SSM:/#{ssm_env}/DOCKER_USER",
    # Use your own docker host
    DOCKER_HOST: "SSM:/#{ssm_env}/DOCKER_HOST",
    JETS_SSH_KEY: "SSM:/#{ssm_env}/JETS_SSH_KEY",
    JETS_SSH_KNOWN: "SSM:/#{ssm_env}/JETS_SSH_KNOWN"
  }
end

This allows you to re-use the same SSM parameters for multiple projects and makes easier to manage and rotate them.

Reference

The table below covers each setting. Each option is configured with config.OPTION. The config. portion is not shown for conciseness. IE: logger.level vs config.logger.level.

Name Default Description
dotenv.ssm.autoload.default_skip see desc Default skip values for SSM autoloading. Default: ["BASIC_AUTH_USERNAME", "BASIC_AUTH_PASSWORD", "BASIC_AUTH_CREDENTIALS"]
dotenv.ssm.autoload.enable true Autoload SSM values from conventional path. IE: /demo/dev/
dotenv.ssm.autoload.skip [] Skip these values for SSM autoloading.
dotenv.ssm.convention_resolver nil A proc that receives ssm_leaf_value as the argument. You can use this to customize the SSM name conventional resolver.
dotenv.ssm.long_env false Useful for legacy Jets 5 behavior, where JETS_ENV was encouraged to be development or production. Jets 6 uses dev and prod.
dotenv.ssm.envs.unique [“dev”,”prod”] The unique env values that should resolve to the SSM env name. So the cases when JETS_ENV is the same as SSM env name.
dotenv.ssm.envs.fallback [“dev”] When JETS_ENV is not one of the ssm.envs.unique envs, then fall back and use this env. IE: JETS_ENV=sandbox resolves to dev for the SSM env name.
dotenv.ssm.project_name nil Override the ssm project name. When not set, defaults to project name set by config.name in config/jets/project.rb.

See Full Config Reference