63

I am trying to use Cisco anyconnect 3.1 from Linux command line to connect to a server. I can connect, but I have to submit one parameter at a time. I would like to connect from a script that will run in another server. Can I do that? Something like

vpn connect server_add group_name user_name passwd
0

10 Answers 10

68

Assuming /opt/cisco/anyconnect/bin/vpnagentd is running as it automatically should be:

To connect:

printf 'USERNAME\nPASSWORD\ny' | /opt/cisco/anyconnect/bin/vpn -s connect HOST

Replace USERNAME, PASSWORD, and HOST. The \ny at the end is to accept the login banner - this is specific to my host.

Note the single quotes ' instead of double quotes " - this is because double quotes tell Bash to interpret certain characters within strings, such as exclamation marks, as Bash history commands. Double quotes will make this command fail with an "event not found" error if the password contains an exclamation mark. Single-quoted strings pass exclamation marks along without interpreting them.

To disconnect:

/opt/cisco/anyconnect/bin/vpn disconnect

This was tested with AnyConnect v3.1.05160.

4
  • 5
    In case your client does not connect due to certificate validation error Certificate is from an untrusted source, and you still want to connect then pass a y parameter in the above method so that the command to connect becomes: printf "y\nUSERNAME\nPASSWORD\ny" | /opt/cisco/anyconnect/bin/vpn -s connect HOST. Note that do this only in the case that you absolutely trust your connection; otherwise there might be a middleman sitting in and snooping onto you.
    – shivams
    Apr 22, 2015 at 11:38
  • 2
    Works beautifully (though my version needs a GROUPNAME\nUSERNAME\nPASSWORDy. If you want to keep your password separate from the command (which may be a shell script or a dotfile key binding), you can do this: cat ~/.anyconnect_credentials | /opt/cisco/anyconnect/bin/vpn -s connect HOST Nov 4, 2019 at 18:08
  • @SridharSarnobat Using a separate file for the credentials works, but it prints out your password in the log like: >> notice: Please respond to banner. MYPASSWORD Nov 19, 2019 at 20:05
  • is there a way to specify the profile from the CLI ? Nov 29, 2021 at 20:59
17

I ran into the same difficulty try to use Cisco AnyConnect from Mac OS X Terminal. To get the Cisco vpn command to take its input from standard input, you have to specify the -s option, which puts the Cisco vpn command into interactive mode. Then you can provide the responses that you give in interactive mode.

The responses that you need to give depend upon how the VPN server administrator has configured the server. For me, the vpn interactive prompts are

Group: 
Username: 
Password: 

Blah, blah, blah, ...
accept? :

So the command that I run is

$ /opt/cisco/anyconnect/bin/vpn -s connect vpn.example.com <<"EOF"
0
username
password
y
exit
EOF

(The quotes around EOF are to prevent command/parameter expansion/substitution in the following input.)

The exit at the end is to exit the Cisco vpn interactive mode.

0
7

You can put your connection info in a separate file, e.g.

anyconnect.txt:

connect [HOST]
[GROUP or 0 or 1]
[USER]
[PASSWORD]
y
exit

And then do:

/opt/cisco/anyconnect/bin/vpn -s < anyconnect.txt
1
  • Hi @Dan, is it also possible to parse the 2nd password? I need to give a 2nd password 'push', which directs anyconnect client a push notification on my phone. While adding 'push' next to the [PASSWORD] line made the vpn client send a push notification to my phone, the client doesn't accept it and I don't know why. Below is my log ... Username: [...] Password: [...] Second Password: >> notice: Hostscan is performing system scan >> notice: Hostscan is performing software scan >> notice: Hostscan state idle >> notice: Hostscan is waiting for the next scan >> Login failed.
    – J-min
    Jul 10, 2021 at 20:53
5

I like to simplify the command line, so I use the above approach in a shell script named gotowork. As above, I need to provide the group, my user name, and a passkey composed of a private PIN plus a RSA SecurID passcode. I don't have to answer the above "accept?" question. Everything but the RSA passcode is in the script, so the command line is

$ gotowork <RSA passcode>

I have to run it as root. Assume the PIN is 1234. The script essentials:

# put the interactive answers into a text file
echo -e "0\nusername\n1234$1\n" > /tmp/answers.txt
# find the path to the anyconnect executables
ciscopath="$(dirname $(find /opt/cisco -depth -name vpnagentd))"
# make sure the anyconnect daemon is running
[ $(pidof vpnagentd) ] || $ciscopath/vpnagentd
# connect
$ciscopath/vpn -s < /tmp/answers.txt connect remote.mycompany.com

Using anyconnect 3.1.05170. Tested on Debian 6, LinuxMint 17

5
  • Why is 0\n necessary? Or is it specific to your company?
    – Asclepius
    Nov 9, 2014 at 5:10
  • @A-B-B That's just saying output a zero 0, followed by a newline \n followed by username, followed by a newline \n etc... Jan 22, 2015 at 21:39
  • @MattFriedman, I know what it's saying, but I don't know why it's necessary at all.
    – Asclepius
    Jan 22, 2015 at 23:02
  • 1
    @A-B-B When running interactively and your connection uses groups, the possible groups will be enumerated. 0 then means "use the first group".
    – jmd_dk
    Mar 6, 2018 at 5:24
  • 1
    Nice one. I did not like providing pin and token via plaintext, so i altered the script as follows: echo -n "Enter PIN :"; read -s PIN; echo; echo -n "Enter RSA token: "; read -s TOKEN; echo -e "0\nusername\n$PIN$TOKEN\n" > /tmp/answers.txt. As well as rm /tmp/answers.txt at the end of the file Aug 4, 2021 at 8:10
4

This is what worked for me on OSX El Capitan. Placeholders are surrounded by [square braces].

To Enable

/opt/cisco/anyconnect/bin/vpn -s connect [HOST_ADDRESS] <<"EOF"
[VPN_USERNAME]
[VPN_PASSWORD] 
y
EOF

To Disable

/opt/cisco/anyconnect/bin/vpn disconnect

*I know this is similar to Peter S.'s answer above.

1
  • 1
    This worked for me in one command for El Capitan, printf "y\n[GROUP]\n\n[PASSWORD]\ny\n" | /opt/cisco/anyconnect/bin/vpn -s connect HOST
    – Rabea
    Nov 23, 2016 at 0:07
2

I had to enter a two-step code, so I had to use the following template.

connect host
username
pass
twostep
y
exit

/opt/cisco/anyconnect/bin/vpn -s < anyconnect.txt


On Mac (Ventura 13.2.1) I wanted to integrate keychain and two-step together so I made the following script. It retrieves the key used for two-step, uses python OTP library to get the two-step code, and also uses keychain to get the password. Then connects to Cisco Connect.

Note that first you need to create the keychain entries as described in the blog referred below. Maybe for testing you can initially hardcode key and password.

Make sure to edit [Username] and [Host]. I had them hardcoded rather than keychain on Mac.

import time
import pyotp
import subprocess

key = subprocess.check_output("security find-generic-password -w -a $LOGNAME -s key", shell=True)[:-1].decode("utf-8")

uri = pyotp.totp.TOTP(key).provisioning_uri()
totp = pyotp.TOTP(key)

key = totp.now()

print(key)

password = subprocess.check_output("security find-generic-password -w -a $LOGNAME -s key_password", shell=True)[:-1].decode("utf-8")


output = subprocess.check_output(f"/opt/cisco/anyconnect/bin/vpn -s connect [Host] <<'EOF'\n[UserName]\n{password}\n{key}\ny\nEOF", shell=True)

print(output)

Ref: https://blog.koehntopp.info/2017/01/26/command-line-access-to-the-mac-keychain.html


Steps to create keychain items :

  1. Add otp_key to keychain :
  • security add-generic-password -T "" -a $LOGNAME -s [hostname_otp] -w [otp_key]
  1. Add password of host :
  • security add-generic-password -T "" -a $LOGNAME -s [hostname_username] -w [host_password]

Steps to retrieve saved key and password :

  1. Retrieve host's otp_key
  • security find-generic-password -w -a $LOGNAME -s [hostname_otp]
  1. Retreive password of hostname_username
  • security find-generic-password -w -a $LOGNAME -s [hostname_username]

This will make sure that there is an extra step to connecting to host, i.e. retrieving secret info from keychain after providing the password, rather than hardcoding in a file.

3
  • Oh thanks! my bad. I expanded the answer for someone who needs to authenticate to cisco anyconnect which requires a two step code as well. Also, if they want to get the two step code automatically, this answer provides a solution for that. Sharing in case anyone wants to do the same (This page was the starting point for me to come up with this answer, so thought to share here). Mar 8, 2023 at 18:05
  • Appreciate it! Now I have expanded to address 1) and 2). If there's any way to improve readability feel free to share your edits. Mar 8, 2023 at 18:31
  • Brilliant, upvoted :-) Mar 8, 2023 at 18:35
1

To avoid hard-coding your password in a plain-text config file or putting it on the command line, you can also integrate with a CLI password manager like pass.

#!/bin/bash

# Easily connect to Cisco AnyConnect VPN

# Get first parameter
COMMAND="$1"

case $COMMAND in
    connect | CONNECT | c | C)
        printf "2\n${username}\n$(pass show my_password_entry)\n" | \
            /opt/cisco/anyconnect/bin/vpn -s connect remote_host_url
        ;;

    disconnect | DISCONNECT | d | D)
        /opt/cisco/anyconnect/bin/vpn disconnect
        ;;

    *)
        cat <<EOF
Usage: vpnctl COMMAND
       connect | CONNECT | c | C    Connect to the VPN
       disconnect | DISCONNECT | d | D    Disconnect from the VPN
EOF
        ;;
esac

The initial 2 in the printf string just selects from a menu which my organization has configured to show up before you can put in your username and password. The exact printf statement may vary for you.

Tested using Cisco AnyConnect 4.10.02086 on Manjaro 21.2.6, with kernel 5.17.9.

0

For this use case, I used expect script. Pasting my solution below:

`#!/usr/bin/expect
spawn sudo /opt/cisco/anyconnect/bin/vpnagentd
expect ": "
send "Sudo Password goes here \r"
expect "$ "
spawn /opt/cisco/anyconnect/bin/vpn -s connect HOST
expect "*]*"
send -- "Username goes here\r"
expect "Password: "
send -- "Password goes here\r"
expect "Answer: "
send -- "If MFA is not enabled, then this step can be skipped\r"
0

Inspired from others answers, I've written a shell script for less key strokes:

#!/usr/bin/env bash

__quickvpn(){
  local username="your_username_here"
  local password="your_pwd_here"
  local url="your_host_here"
  local vpn_tool="/opt/cisco/anyconnect/bin/vpn"
  if [[ -z $1 && -e /opt/cisco/anyconnect/bin/vpn ]];then
    echo "usage: on | off | state \n - on: connect\n - off: disconnect\n - state: connect status\n"
  elif [[ $1 == "on" ]];then
    print "${username}\n${password}\ny" | $vpn_tool -s connect $url > /dev/null 2>&1
  elif [[ $1 == "off" ]]; then
    print "${username}\n${password}\ny" |  $vpn_tool -s disconnect $url > /dev/null 2>&1
  elif [[ $1 == "state" ]]; then
    $vpn_tool -s state | sed 's/>>//' | sed -n 's/\(state:.*\).*/\1/p;/state/q'
  else
    echo "cisco vpn not found"
  fi
}

__quickvpn $1

Save above as a shell script file named as myvpn under /usr/local/bin and chmod 744 /usr/local/bin/myvpn then you could use it like:

myvpn on # connect
myvpn off # disconnect
myvpn state # connection status
0

This is what worked on MacOS Monterey:

#connect to vpn 
cvpn() {
    printf 'y\n[your username]\n[password]\ny' | /opt/cisco/anyconnect/bin/vpn -s connect  <vpn dns/url>
}

#disconnect to vpn
dvpn() {
    /opt/cisco/anyconnect/bin/vpn disconnect
}
1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Apr 15, 2022 at 3:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .