Skip to content

Instantly share code, notes, and snippets.

@xbb
Created December 5, 2023 12:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xbb/fb0e20812fb305a55c57cb03c4d8d475 to your computer and use it in GitHub Desktop.
Save xbb/fb0e20812fb305a55c57cb03c4d8d475 to your computer and use it in GitHub Desktop.
Login to Teleport with 1Password CLI
#!/usr/bin/env bash
set -e
main() {
case $1 in
help) show_help ;;
*) load_profile "$1" ;;
esac
set -u
run
}
show_help() {
echo "Usage: $(basename "${BASH_SOURCE[0]}")" '<profile_name>'
show_help_profile
}
show_help_profile() {
cat <<'EOF'
Profiles are bash scripts sourced from:
~/.config/op-tsh-login/<profile_name>
Example configuration:
# 1password account login url
export OPTP_ACCOUNT_URL='example.1password.com'
# 1password item field path op://<vault>/<item>/<field>
export OPTP_USER='op://Private/Teleport/username'
export OPTP_PASS='op://Private/Teleport/password'
# Teleport proxy URL
export OPTP_PROXY='teleport.example.com'
EOF
}
load_profile() {
if test -z "$1"; then
>&2 show_help
exit 1
fi
if [[ "$1" =~ [^a-zA-Z0-9] ]]; then
>&2 echo "Invalid profile name: $1"
exit 1
fi
local config_dir="$HOME/.config/op-tsh-login"
local profile="$config_dir/$1"
if ! test -d "$config_dir"; then
mkdir -p "$config_dir"
fi
if ! test -f "$profile"; then
>&2 echo "Error: $profile does not exist"
>&2 show_help_profile
exit 1
fi
source "$profile"
}
tsh_status() {
tsh status 2>&1
}
check_status() {
local status=
status="$(tsh_status)" || return 0
>&2 printf "Already logged in:\n\n%s\n" "$status"
>&2 printf "\nTo logout use:\n\n tsh logout\n"
return 2
}
run() {
check_status
op run -- expect -c "$(cat <<'EOF'
set USERNAME $env(TP_USER)
spawn tsh login --proxy "$env(TP_PROXY)" --user "$env(TP_USER)"
expect -re "Enter password for Teleport user $USERNAME*" {
send -- "$env(TP_PASS)\n"
interact
}
EOF
)"
}
main "$@"
@wSedlacek
Copy link

I updated this for fish with a few enhancements like colors, formatting, otp, a single env variable.

There are some limitations like how op get item only will look at domain name (not sub domains). I haven't added handling for when multiple items match, so that may be a future enhancement if I end up with more entries on the same domain name.
This also doesn't handle cases where a user isn't using a otp.

function teleport_login -d "Automate login to Teleport using 1Password credentials"
    for arg in $argv
        switch $arg
            case '--help'
                set_color cyan; echo "Teleport Login Automation Script"; set_color normal
                echo "Usage:"
                set_color yellow; echo "    teleport_login [--help]"; set_color normal
                echo ""
                set_color cyan; echo "Environment Variables:"; set_color normal
                set_color green
                echo "    OPTP_PROXY"
                echo "        Description: Identifier for the 1Password item containing Teleport credentials."
                echo "        Example: set -gx OPTP_PROXY 'teleport.example.com'"
                set_color normal
                return
        end
    end

    if not set -q OPTP_PROXY
        echo "OPTP_PROXY environment variable not set. Run 'teleport_login --help' for more information." >&2
        return 1
    end


    # Teleport login logic
    set -l teleport_status
    tsh status 2>&1 | read -z teleport_status

    if string match -q "*Logged in as*" $teleport_status
        if not string match -q "*[EXPIRED]*" $teleport_status
            # Print colored header
            set_color magenta
            echo "You are already logged in to Teleport:"
            set_color normal
            echo ""

            # Print each line of the teleport_status directly
            for line in (string split \n $teleport_status)
                # Skip lines that are empty or consist of whitespace only
                if not string match -q -r '\S' $line
                    continue
                end

                echo $line
            end

            # Print colored footer
            echo ""
            set_color yellow
            echo "To logout, use this command:"
            set_color green
            echo "tsh logout"
            set_color normal
            return 2
        end
    end

    # Extract the top-level domain from OPTP_PROXY
    set -l domain_parts (string split '.' $OPTP_PROXY)
    set -l tld (string join '.' $domain_parts[-2..-1])

    # Fetch item from 1Password using the top-level domain
    set -l item (op item get $tld)
    if not test $status -eq 0
        echo "Failed to get item from 1Password for TLD $tld" >&2
        return 1
    end

    set -l username (echo $item | string match -r 'username:\s+\S+' | string trim | string replace -r 'username:\s+' '')
    set -l password (echo $item | string match -r 'password:\s+\S+' | string trim | string replace -r 'password:\s+' '')
    set -l otp (echo $item | string match -r 'one-time password:\s+\S+' | string trim | string replace -r 'one-time password:\s+' '')

    if not set -q username
        echo "Username not found in 1Password item for $OPTP_PROXY" >&2
        return 1
    end

    if not set -q password
        echo "Password not found in 1Password item for $OPTP_PROXY" >&2
        return 1
    end

    if not set -q otp
        echo "One-time password not found in 1Password item for $OPTP_PROXY" >&2
        return 1
    end


    expect -c "
        log_user 0
        spawn tsh login --proxy $OPTP_PROXY --user $username
        expect {
            -re \"Enter password for Teleport user $username:\" {
                send -- \"$password\r\"
                exp_continue
            }
            -re \"Enter an OTP code from a device:\" {
                send -- \"$otp\r\"
            }
        }
        interact
    "
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment