0

I need to run a command inside a bash -c "..." construct. The actual command calls the Vault CLI tool to generate a TLS certificate. The important thing to note is that the CLI tool requires that a variable called VAULT_TOKEN be set.

For the sake of this example, assume that there are files in the local directory called token and options, with data that Vault requires. These are not relevant to the question.

My script:

/bin/bash -c "export VAULT_TOKEN=$(cat token); \
    CERT_OPTIONS=$(cat options); \
    CERT=\"$(echo \$CERT_OPTIONS | vault write pki/issue/default -format=json -)\"; \
    echo cert=\$CERT"

The last statement in the command (echo cert=\$CERT) is simply a placeholder to demonstrate the problem, normally I would make use the value of $CERT.

My understanding of how the above should work (based on a very imperfect knowledge of Bash):

  1. Bash is called and treats the contents of the "..." string as a script. That script will then action the below:
  2. Get the token from the file called token, export this value into a variable so that sub-processes can access it (hence the use of export).
  3. Get the options from a file and put into a shell variable that is visible at the scope of the contents of the bash -c script.
  4. Launch a separate process via command substitution that will call Vault, and $VAULT_TOKEN should be visible to this process as it is a child process of the script that bash -c runs.

What I see, however, is an error that indicates that $VAULT_TOKEN is not set, i.e. the vault CLI tool throws an error saying it doesn't have a value for $VAULT_TOKEN.

When I simplify the command further to be:

/bin/bash -c "export VAULT_TOKEN=$(echo token); \
    CERT=\"$(echo \$VAULT_TOKEN > /tmp/test.out)\"; \
    echo cert=\$CERT"

I can see:

> cat /tmp/test.out
$VAULT_TOKEN

...not token that I was expecting.

I escaped the echo of VAULT_TOKEN (via echo \$VAULT_TOKEN), because otherwise I believe that it will be replaced by Bash with the value of $VAULT_TOKEN from my shell (which is not set), so I get an empty string in /tmp/test.out.

Clearly my understanding of command substitution/variable evaluation is wrong - please can someone advise on the below:

  1. Why is $VAULT_TOKEN not visible in the $(...) command substitution?
  2. How do I make $VAULT_TOKEN visible to the vault command?

For other reasons, I must run this set of commands in a bash -c manner, so I can't separate out the commands into a script.

John
  • 10,837
  • 17
  • 78
  • 141
  • 2
    The commands are not evaluated by the bash you start but by your shell. Try replacing bash -c "..." with bash -c '...' – Jan Matějka Jan 05 '19 at 14:01
  • `CERT="$(echo $VAULT_TOKEN > test.out)"` CERT will be empty because you are redirecting the output to `test.out`. Otherwise, replace the outer double quotes with single quotes and remove the \ escapes before each `$`. – cdarke Jan 05 '19 at 14:05
  • @yaccz Thanks, that's exactly the issue. – John Jan 05 '19 at 14:07
  • You *never* need to change your code's quoting for `bash -c` use manually -- let the shell do that for you. `mycode() { code "with" 'unmodified' "quoting"; }; bash -c "$(declare -f mycode); mycode"` – Charles Duffy Jan 05 '19 at 15:47

0 Answers0