Issue
I have this script:
#!/bin/bash
TOKEN='faketokendgfhjkdhf'
KEYNAME="test_$(date +'%m-%Y')"
echo $KEYNAME
KEYPATH="$HOME/.ssh/${KEYNAME}"
echo $KEYPATH
SSHPHRASE="testphrase123!"
ssh-keygen -t ed25519 \
-f $KEYPATH \
-C $KEYNAME \
-N "$SSHPHRASE"
echo $KEYPATH
cat "$KEYPATH".pub
PUBKEY="$(cat $KEYPATH.pub)"
echo "$PUBKEY"
read -r -d '' SSH_KEY_REQ <<EOF
{"labels":{},\
"name":"$KEYNAME",\
"public_key":"$(echo "$PUBKEY")"}
EOF
echo $SSH_KEY_REQ
curl \
-X POST \
-H "Authorization: Bearer "$TOKEN"" \
-H "Content-Type: application/json" \
-d $SSH_KEY_REQ \
"https://api.example.com/v1/ssh_keys"
However, when I run the script it fails with
curl: (6) Could not resolve host: AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE
curl: (3) unmatched close brace/bracket in URL position 14:
test_01-2024"}
So I ran the script with -x
in order to see what strings were actually being created, and it seems a '
is being inserted into the string for public_key
.
$ sh -x htest.sh $PARENTPATH/Secret/variables.sh
sh -x htest.sh $PARENTPATH/Secret/variables.sh
+ TOKEN=faketokendgfhjkdhf
++ date +%m-%Y
+ KEYNAME=test_01-2024
+ echo test_01-2024
test_01-2024
+ KEYPATH=/home/jam/.ssh/test_01-2024
+ echo /home/jam/.ssh/test_01-2024
/home/jam/.ssh/test_01-2024
+ SSHPHRASE='testphrase123!'
+ ssh-keygen -t ed25519 -f /home/jam/.ssh/test_01-2024 -C test_01-2024 -N 'testphrase123!'
Generating public/private ed25519 key pair.
/home/jam/.ssh/test_01-2024 already exists.
Overwrite (y/n)? y
Your identification has been saved in /home/jam/.ssh/test_01-2024
Your public key has been saved in /home/jam/.ssh/test_01-2024.pub
The key fingerprint is:
SHA256:ycI4fnxQSo1NDiQ/lLXUcVcJrhsnsPFzkqlO8uAI6qs test_01-2024
The key's randomart image is:
+--[ED25519 256]--+
| ..+o+.....o.o|
| +.O ..... . |
| = *o . |
| + = .= + |
| o = S. X o |
| . o o . O |
| .. oo.o . |
| . ..o.* |
|E+. . . o |
+----[SHA256]-----+
+ echo /home/jam/.ssh/test_01-2024
/home/jam/.ssh/test_01-2024
+ cat /home/jam/.ssh/test_01-2024.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024
++ cat /home/jam/.ssh/test_01-2024.pub
+ PUBKEY='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024'
+ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024
+ read -r -d '' SSH_KEY_REQ
++ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024'
+ echo '{"labels":{},"name":"test_01-2024","public_key":"ssh-ed25519' AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi 'test_01-2024"}'
{"labels":{},"name":"test_01-2024","public_key":"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024"}
+ curl -X POST -H 'Authorization: Bearer faketokendgfhjkdhf' -H 'Content-Type: application/json' -d '{"labels":{},"name":"test_01-2024","public_key":"ssh-ed25519' AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi 'test_01-2024"}' https://api.example.com/v1/ssh_keys
curl: (6) Could not resolve host: AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE
curl: (3) unmatched close brace/bracket in URL position 14:
test_01-2024"}
^
The use of read
and/or the use of a heredoc seems to be where the unwanted '
comes in:
+ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024
+ read -r -d '' SSH_KEY_REQ
++ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi test_01-2024'
+ echo '{"labels":{},"name":"test_01-2024","public_key":"ssh-ed25519' AAAAC3NzaC1lZDI1NTE5AAAAIJ88fLX9FgVC8poMyfuMFuE/DFtXlaer9LY/WfHnoIOi 'test_01-2024"}'
I am unclear as to how/why this happens. My goal is to use the json string with the unmodified pubkey in SSH_KEY_REQ
such that the curl
command actually run is:
curl -X POST -H 'Authorization: Bearer faketokendgfhjkdhf' -H 'Content-Type: application/json' -d '{"labels":{},"name":"test_01-2024","public_key":"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMu4pDny1/78PYQBcu6kPs+n2e0Jt9goIyDMqFcndFPI test_01-2024"}' https://api.example.com/v1/ssh_keys
After using spellcheck.net as suggested in the comments, it now works as desired with:
#!/bin/bash
TOKEN='faketokendgfhjkdhf'
KEYNAME="test_$(date +'%m-%Y')"
echo "$KEYNAME"
KEYPATH=$HOME/.ssh/${KEYNAME}
echo "$KEYPATH"
SSHPHRASE="testphrase123!"
ssh-keygen -t ed25519 \
-f "$KEYPATH" \
-C "$KEYNAME" \
-N "$SSHPHRASE"
echo " $KEYPATH"
cat "$KEYPATH".pub
PUBKEY="$(cat "$KEYPATH.pub")"
echo "$PUBKEY"
read -r -d '' SSH_KEY_REQ <<EOF
{"labels":{},\
"name":"$KEYNAME",\
"public_key": "$PUBKEY")"}
EOF
echo "$SSH_KEY_REQ"
curl \
-X POST \
-H "Authorization: Bearer \"$TOKEN\"" \
-H "Content-Type: application/json" \
-d "$SSH_KEY_REQ" \
"https://api.example.com/v1/ssh_keys"
Solution
The string doesn't really have a '
in it. That's how Bash is representing multiple arguments being passed to a command.
Here's a simplified example to show what I mean:
set -x
PUBKEY="TEST bar"
read -r -d '' SSH_KEY_REQ <<EOF
{"public_key":"$PUBKEY"}
EOF
echo $SSH_KEY_REQ
This prints the following:
+ PUBKEY='TEST bar'
+ read -r -d '' SSH_KEY_REQ
+ echo '{"public_key":"TEST' 'bar"}'
{"public_key":"TEST bar"}
Notice that a '
appeared in the middle of the substituted string on line 3. But the '
didn't appear alone - there are actually 4 '
characters. If you look closely at the output of your example, the same thing is happening at the beginning and end.
Bash is performing word splitting because $SSH_KEY_REQ was not quoted. If you change echo $SSH_KEY_REQ
to echo "$SSH_KEY_REQ"
, it will stop breaking up the key into multiple arguments.
Some other things you should keep in mind:
$(echo $VAR)
is redundant, and it can be simplified to$VAR
.
Answered By - Nick ODell Answer Checked By - Marie Seifert (WPSolving Admin)