Grab an IdentityFile from an ssh config based on a variable hostname via shell script
Asked Answered
I

3

5

I'm writing a shell script where I need to obtain an IdentityFile from an ssh config file. The ssh config file looks like this:

​Host AAAA
    User aaaa
    IdentityFile /home/aaaa/.ssh/aaaaFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey
​Host BBBB
    User bbbb
    IdentityFile /home/aaaa/.ssh/bbbbFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey
​Host CCCC
    User cccc
    IdentityFile /home/aaaa/.ssh/ccccFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey

I want to obtain the string following IdentityFile based on a given Hostname and put it in a variable. The hostname will be provided by a shell variable called ${HOSTNAME}.

I was able to use the answer at Bash extract user for a particular host from ssh config file to read the config file and grep for a single specific IdentityFile based on a single specific Hostname, but I can't get the hang of passing a variable into awk.

So far I've tried

SSH_CONFIG="/home/aaaa/.ssh/config"
# Note AAAA is the hostname for this case
KEY=$(awk '/^Host AAAA$/{x=1}x&&/IdentityFile/{print $2;exit}' ${SSH_CONFIG})
echo "${KEY}" 

OUTPUT: "/home/aaaa/.ssh/aaaaFILE"

which works because I'm giving the exact hostname to parse. But using

SSH_CONFIG="/home/aaaa/.ssh/config"
HOSTNAME=AAAA
KEY=$(awk -vcon="${HOSTNAME}" '/^Host con$/{x=1}x&&/IdentityFile/{print $2;exit}' ${SSH_CONFIG})
echo "${KEY}" 

OUTPUT: ""

does not work. I know for a fact ${HOSTNAME} is being set because I am setting myself (and echoing it). I would like to pass a variable because I do not want the hostname hardcoded and will not know what the value is until the script is called.

I am also stuck using and older version of ssh (OpenSSH_6.6.1) which does not have the convenient ssh -G HOSTNAME option.

What am I missing when it comes to awk variables? Is there a better way to do this?

Indocile answered 14/8, 2017 at 20:42 Comment(0)
M
2

With GNU grep and Perl Compatible Regular Expressions:

hostname="AAAA"
grep -Poz "Host $hostname(.*\n)*?.*IdentityFile \K.*" ~aaaa/.ssh/config

Output:

/home/aaaa/.ssh/aaaaFILE
Melancholic answered 14/8, 2017 at 20:52 Comment(1)
Thanks for this suggestion @Cyrus. This worked for me. I'm choosing your answer because grep allows for more brevity.Indocile
U
5

I appreciate the scripting attempts, but OpenSSH client already knows how to parse the configuration:

ssh -G $hosname | grep identityfile | awk '{print $2}' | head -n 1

note, that it will also list the default identities, but with IdentitiesOnly=yes it should list the one from configuration as the first one.

Udder answered 15/8, 2017 at 10:57 Comment(3)
As I mentioned above, I am also stuck using and older version of ssh (OpenSSH_6.6.1) which does not have the convenient ssh -G HOSTNAME option. Unless you would like to roll a Debian package for me, I am stuck scripting sans ssh -G.Indocile
@Indocile sorry, I missed that part. Maybe time to update?Udder
That's unfortunately not my decision to make, but trust me, I'd love to update. I've already been dinged with not having a verbose option for sshpass because of this too.Indocile
M
2

With GNU grep and Perl Compatible Regular Expressions:

hostname="AAAA"
grep -Poz "Host $hostname(.*\n)*?.*IdentityFile \K.*" ~aaaa/.ssh/config

Output:

/home/aaaa/.ssh/aaaaFILE
Melancholic answered 14/8, 2017 at 20:52 Comment(1)
Thanks for this suggestion @Cyrus. This worked for me. I'm choosing your answer because grep allows for more brevity.Indocile
G
1

mmm for some reason, the example you posted has strange non-printable characters before Host word. This regular expression only matched the first line: /^Host/, while it should match 3 total lines.

I fixed that by deleting those characters and saving it again.

So, answering your question, you can't use variables inside a regular expression in awk.

But this also works and do the same:

HOSTNAME="BBBB"
awk -v host=$HOSTNAME '/Host/ && $2==host {found=1} /IdentityFile/ && found {print $2; exit}' ${SSH_CONFIG}
Garrard answered 14/8, 2017 at 22:53 Comment(1)
Thanks for this suggestion @valrog. This worked for me.Indocile

© 2022 - 2024 — McMap. All rights reserved.