-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbw-ssh-add
executable file
·178 lines (155 loc) · 4.73 KB
/
bw-ssh-add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env bash
set -euo pipefail
#
# bw-ssh-add - https://github.com/elasticdog/bw-ssh-add
#
# This script adds a passphrase-protected SSH key to your local `ssh-agent`
# by leveraging credentials stored in Bitwarden. It securely retrieves
# the passphrase via the Bitwarden CLI, then uses `expect` to automate the
# authentication process with `ssh-add`.
#
# Usage: bw-ssh-add <BITWARDEN-ITEM-ID> [SSH-ADD-ARGUMENTS...]
#
# - The first argument serves as input for `bw get password`, either as a search
# term or as an item's globally unique identifier, to retrieve the key's
# passphrase.
# - Any additional arguments are passed through to `ssh-add` unchanged. Refer to
# the `ssh-add` man page for details on available options.
#
# The script sets an expiration time for the added key:
#
# - Default: 17:00:00 (5:00 PM local time)
# - If it's already past 5:00 PM: 3 hours
# - Customize the end-of-day time using the `BW_SSH_ADD_EOD` environment variable
# (format: HH:MM:SS)
# - To remove the maximum lifetime, set `BW_SSH_ADD_EOD` to an empty string
#
# Examples:
#
# bw-ssh-add "My SSH Key"
# bw-ssh-add 99ee88d2-6046-4ea7-92c2-acac464b1412
# bw-ssh-add "Work Laptop Key" -t 3600
# BW_SSH_ADD_EOD="18:30:00" bw-ssh-add "Custom EOD Key"
# BW_SSH_ADD_EOD="" bw-ssh-add "No Expiry Key"
#
# Requirements:
#
# - Bitwarden CLI (`bw`) installed and configured
# - `expect` command available
# - SSH agent running
#
# This source code is released under the Zero Clause BSD License (SPDX: 0BSD).
# Copyright (c) 2024 Aaron Bull Schaefer and contributors
#
##### FUNCTIONS
calculate_seconds_until_eod() {
local eod_time
local current_epoch
local today
local today_at_eod_epoch
local seconds_until_eod
# If BW_SSH_ADD_EOD is set to an empty string, return -1 to indicate no expiration
if [[ -n ${BW_SSH_ADD_EOD+x} ]] && [[ -z $BW_SSH_ADD_EOD ]]; then
printf "%d" -1
return
fi
# Use BW_SSH_ADD_EOD if set, otherwise default to 17:00:00 (5:00 PM)
eod_time=${BW_SSH_ADD_EOD:-"17:00:00"}
current_epoch=$(date +%s)
today=$(date +%Y-%m-%d)
today_at_eod_epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "${today} ${eod_time}" +%s)
seconds_until_eod=$((today_at_eod_epoch - current_epoch))
if ((seconds_until_eod > 0)); then
printf "%d" "$seconds_until_eod"
else
printf "%d" $((3 * 3600)) # Default to 3 hours if after EOD
fi
}
ensure_bitwarden_unlocked() {
if ! bw login --check >/dev/null 2>&1; then
printf "Error: You are not logged in to Bitwarden. Please run 'bw login' first.\n" >&2
exit 1
fi
if ! bw unlock --check >/dev/null 2>&1; then
printf "Bitwarden vault is locked. Attempting to unlock...\n"
printf "Please enter your master password when prompted.\n"
export BW_SESSION
BW_SESSION=$(bw unlock --raw)
fi
}
add_ssh_key() {
local bw_id=$1
shift
local bw_password
local ssh_add_args="$*"
bw_password=$(bw get password "$bw_id") || {
printf "Error: Failed to retrieve password from Bitwarden.\n" >&2
exit 1
}
expect -f <(
cat <<-'EOF'
set timeout 60
# Get ssh-add arguments from first line of stdin
set args [gets stdin]
# Get password from second line of stdin
set password [gets stdin]
spawn ssh-add {*}$args
# Expect the passphrase prompt and handle completion
expect {
"Enter passphrase" {
log_user 0
send -- "$password\r"
log_user 1
exp_continue
}
"Identity added" {
# Success case
}
timeout {
puts "Error: Timed out waiting for ssh-add to complete."
exit 1
}
eof {
puts "Error: ssh-add process ended unexpectedly."
exit 1
}
}
EOF
) <<-EOI
$ssh_add_args
$bw_password
EOI
}
##### MAIN
# Check for dependencies
for cmd in {bw,expect,ssh-add}; do
if ! command -v "$cmd" &>/dev/null; then
printf "Error: required command '%s' was not found. Please install it and try again.\n" "$cmd" >&2
exit 1
fi
done
# Validate environment's end-of-day format if set
if [[ -n ${BW_SSH_ADD_EOD:-} ]]; then
if ! [[ $BW_SSH_ADD_EOD =~ ^([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$ ]]; then
printf "Error: Invalid BW_SSH_ADD_EOD format.\n" >&2
printf "Please use HH:MM:SS (e.g., 17:00:00) with hours from 00 to 23,\n" >&2
printf "or an empty string to remove the maximum lifetime limit.\n" >&2
exit 1
fi
fi
# Ensure required Bitwarden item identifier is provided
if [[ $# -lt 1 ]]; then
printf "Usage: %s <BITWARDEN-ITEM-ID> [SSH-ADD-ARGUMENTS...]\n" "${0##*/}" >&2
exit 1
fi
bw_id=$1
shift
# Determine whether to add a lifetime to the ssh-add command
lifetime=$(calculate_seconds_until_eod)
if [[ $lifetime -eq -1 ]]; then
ssh_add_args=("$@")
else
ssh_add_args=("-t" "$lifetime" "$@")
fi
ensure_bitwarden_unlocked
add_ssh_key "$bw_id" "${ssh_add_args[@]}"