OpenVPN prompts for a username and password on the controlling terminal, and a file redirected into standard input is not that terminal. That one detail explains the script that hangs with the password sitting right there in the pipe. The prompt is drawn by the client and the read is taken from the terminal device, so redirecting stdin changes nothing. Feed the client through one of its documented input seams and the same script connects on the first try.

Three seams cover almost every case, and each fails in its own way. Pick by the prompt the client actually shows, not by whichever option is easiest to script.

The prompt does not come from stdin

When OpenVPN needs credentials it opens the controlling terminal and reads there. That is why an interactive test looks fine and the same command under cron or a unit file sits idle with the prompt written to a log nobody is watching. A few builds fall back to standard input when no terminal exists, and that inconsistency is worse than a hard failure because it hides the problem until deployment.

Check the environment before writing any code: run the client under the same user, with the same stdin, as the scheduler or service manager will. If the prompt never appears in the log and the process makes no progress, something is waiting on a terminal that does not exist.

Seam one: a two-line credentials file

The authentication option takes a path, and the file holds exactly two lines, username then password, with nothing else in it. Pass the path explicitly instead of relying on a default filename, because a stray credential file in the working directory is how the wrong account ends up in use. Set the mode to 0600 and give ownership to the account that runs the client.

The client reads that file once at startup, so rotating the password means restarting the process. That is usually the behaviour you want, and it belongs in the runbook next to the rotation procedure.

Seam two: askpass for the key passphrase

A passphrase-protected private key raises a second, different prompt, and it has its own file-backed answer: the askpass option reads the passphrase from the first line of a file. For SSH-based tunnels the equivalent is an askpass program that the client executes, whose standard output becomes the secret.

Neither form puts the secret in the argument list, and both leave it existing as a file or as an executable that prints it. The protection is file permissions and process ownership, not obscurity. A helper that echoes a hardcoded string is a secret with extra steps.

Seam three: the portal client's own CLI

Enterprise clients usually ship a command-line entry point that connects to a named portal with no window involved, and that is the supported path. On Linux the GlobalProtect client exposes connect and import-certificate operations through its CLI, and portals that use certificate authentication need the import step before an automated connect can work. Prefer it to synthesised keystrokes: you get a real exit status, no dependence on window focus, and it survives a locked screen.

If the first connection still needs a human to accept a certificate, the automation is not finished. Do the import during setup and record it as a prerequisite.

When the flow needs a pseudo-terminal

A sequence that asks for a password and then a one-time code has no single file to read. A terminal driver such as Expect is the right tool because it waits for each pattern in turn, and it needs the process started before it can match anything at all.

Two failures dominate. A script that waits for a prompt without spawning the client waits forever, and Tcl is not a shell, so shell arithmetic written inside an expect block does not evaluate the way it reads. Keep the debug flag on while you build the patterns, then turn it off.

Secrets that leak, and where they hide

Anything passed as an argument is visible in the process list, so credentials belong in a file or behind a helper, never on the command line. One-time codes are consumed by design and have to be produced for each attempt. Failure logs often carry the username and sometimes more, so redact before shipping them anywhere, and keep the secret out of the profile itself, because a configuration file with an embedded password gets pasted into tickets and repositories. Rotating the account then means hunting every copy, which is exactly the cost this layout avoids.

Audit the seams you chose, then wire them into the unit file or scheduler that will actually run the client. The tunnel lives exactly as long as that process does.

Mikanda mikatakata