manheim / terraform-pipeline

A reusable pipeline library to apply terraform configuration serially across multiple environments, using Jenkins and a Jenkinsfile.
Apache License 2.0
66 stars 52 forks source link

Add ability to prefix all terraform commands with a string #315

Open jantman opened 3 years ago

jantman commented 3 years ago

I'll say right off the bat, that this is really because my team isn't using Parameter Store the "right" way, and we have lots of things in PS that are laid out in a way that's most logical for humans and not for machines... and we also don't duplicate parameters.

So, we currently have a snippet like this:

ParameterStoreBuildWrapperPlugin
  .withGlobalParameter(
    '/secret/teams/myteam/api_keys/datadog_api_key',
    [naming: 'absolute', recursive: true]
  )
  .withGlobalParameter(
    '/secret/teams/myteam/accounts/neustar-ultradns',
    [naming: 'absolute', recursive: true]
  )
  .withGlobalParameter(
    '/secret/teams/myteam/apps/foobar/datadog_app_key',
    [naming: 'absolute', recursive: true]
  )
  .init()

Note that some of these are hierarchies of parameters, but some are individual parameters. With our PS layout, this results in the following environment variables:

SECRET_TEAMS_MYTEAM_API_KEYS_DATADOG_API_KEY
SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_USERNAME
SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_PASSWORD
SECRET_TEAMS_MYTEAM_APPS_FOOBAR_DATADOG_APP_KEY

However, these are obviously not the environment variable names that the terraform providers expect. They expect DD_API_KEY, ULTRADNS_USERNAME, ULTRADNS_PASSWORD, and DD_APP_KEY, respectively.

We don't want to change our PS layout just to make it work the way plugins expect, so right now with our current tooling, we pass in a string prefix to prepend to all terraform commands, which results in commands like:

set +x;
export DD_API_KEY=$SECRET_TEAMS_MYTEAM_API_KEYS_DATADOG_API_KEY;
export ULTRADNS_USERNAME=$SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_USERNAME;
export ULTRADNS_PASSWORD=$SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_PASSWORD;
export DD_APP_KEY=$SECRET_TEAMS_MYTEAM_APPS_FOOBAR_DATADOG_APP_KEY;
set -x;
terraform ...
jantman commented 3 years ago

It turns out that, contrary to what I thought, this can be accomplished via the normal, existing environment variable support.

Using the example in the description of this issue, the desired result can be achieved via:

ParameterStoreBuildWrapperPlugin
  .withGlobalParameter(
    '/secret/teams/myteam/api_keys/datadog_api_key',
    [naming: 'absolute', recursive: true]
  )
  .withGlobalParameter(
    '/secret/teams/myteam/accounts/neustar-ultradns',
    [naming: 'absolute', recursive: true]
  )
  .withGlobalParameter(
    '/secret/teams/myteam/apps/foobar/datadog_app_key',
    [naming: 'absolute', recursive: true]
  )
  .init()

TerraformEnvironmentStage
  .withGlobalEnv('DD_API_KEY', '$SECRET_TEAMS_MYTEAM_API_KEYS_DATADOG_API_KEY')
  .withGlobalEnv('ULTRADNS_USERNAME', '$SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_USERNAME')
  .withGlobalEnv('ULTRADNS_PASSWORD, '$SECRET_TEAMS_MYTEAM_ACCOUNTS_NEUSTAR_ULTRADNS_ULTRADNS_PASSWORD')
  .withGlobalEnv('DD_APP_KEY', '$SECRET_TEAMS_MYTEAM_APPS_FOOBAR_DATADOG_APP_KEY')
jantman commented 3 years ago

Well, this is rather embarrassing. It appears that my statement about being able to do this with normal environment variable support was wrong... or at least I did something non-obvious that's preventing it from working. In that case, the environment variables are just set to the literal, non-interpolated string.

That being said, the classes for Init, Plan, and Apply commands already have support for prefixes and suffixes on the command. We'd just need a plugin that exposes those.