Add support for multiple SSH keys
The --ssh-key-file flag can be specified more than once and the GITSYNC_SSH_KEY_FILE env var will be parsed like PATH. Also adds e2e coverage for wrong-key and for multiple keys.
This commit is contained in:
parent
50de3aaeab
commit
29b291e9c2
|
|
@ -317,8 +317,10 @@ OPTIONS
|
||||||
Use SSH for git authentication and operations.
|
Use SSH for git authentication and operations.
|
||||||
|
|
||||||
--ssh-key-file <string>, $GITSYNC_SSH_KEY_FILE
|
--ssh-key-file <string>, $GITSYNC_SSH_KEY_FILE
|
||||||
The SSH key to use when using --ssh. If not specified, this
|
The SSH key(s) to use when using --ssh. This flag may be specified
|
||||||
defaults to "/etc/git-secret/ssh".
|
more than once and the environment variable will be parsed like
|
||||||
|
PATH - using a colon (':') to separate elements. If not specified,
|
||||||
|
this defaults to "/etc/git-secret/ssh".
|
||||||
|
|
||||||
--ssh-known-hosts, $GITSYNC_SSH_KNOWN_HOSTS
|
--ssh-known-hosts, $GITSYNC_SSH_KNOWN_HOSTS
|
||||||
Enable SSH known_hosts verification when using --ssh. If not
|
Enable SSH known_hosts verification when using --ssh. If not
|
||||||
|
|
|
||||||
45
main.go
45
main.go
|
|
@ -118,6 +118,23 @@ func envString(def string, key string, alts ...string) string {
|
||||||
return def
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func envStringArray(def string, key string, alts ...string) []string {
|
||||||
|
parse := func(s string) []string {
|
||||||
|
return strings.Split(s, ":")
|
||||||
|
}
|
||||||
|
|
||||||
|
if val := os.Getenv(key); val != "" {
|
||||||
|
return parse(val)
|
||||||
|
}
|
||||||
|
for _, alt := range alts {
|
||||||
|
if val := os.Getenv(alt); val != "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "env %s has been deprecated, use %s instead\n", alt, key)
|
||||||
|
return parse(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parse(def)
|
||||||
|
}
|
||||||
|
|
||||||
func envBoolOrError(def bool, key string, alts ...string) (bool, error) {
|
func envBoolOrError(def bool, key string, alts ...string) (bool, error) {
|
||||||
parse := func(val string) (bool, error) {
|
parse := func(val string) (bool, error) {
|
||||||
parsed, err := strconv.ParseBool(val)
|
parsed, err := strconv.ParseBool(val)
|
||||||
|
|
@ -437,9 +454,9 @@ func main() {
|
||||||
flSSH := pflag.Bool("ssh",
|
flSSH := pflag.Bool("ssh",
|
||||||
envBool(false, "GITSYNC_SSH", "GIT_SYNC_SSH"),
|
envBool(false, "GITSYNC_SSH", "GIT_SYNC_SSH"),
|
||||||
"use SSH for git operations")
|
"use SSH for git operations")
|
||||||
flSSHKeyFile := pflag.String("ssh-key-file",
|
flSSHKeyFiles := pflag.StringArray("ssh-key-file",
|
||||||
envString("/etc/git-secret/ssh", "GITSYNC_SSH_KEY_FILE", "GIT_SYNC_SSH_KEY_FILE", "GIT_SSH_KEY_FILE"),
|
envStringArray("/etc/git-secret/ssh", "GITSYNC_SSH_KEY_FILE", "GIT_SYNC_SSH_KEY_FILE", "GIT_SSH_KEY_FILE"),
|
||||||
"the SSH key to use")
|
"the SSH key(s) to use")
|
||||||
flSSHKnownHosts := pflag.Bool("ssh-known-hosts",
|
flSSHKnownHosts := pflag.Bool("ssh-known-hosts",
|
||||||
envBool(true, "GITSYNC_SSH_KNOWN_HOSTS", "GIT_SYNC_KNOWN_HOSTS", "GIT_KNOWN_HOSTS"),
|
envBool(true, "GITSYNC_SSH_KNOWN_HOSTS", "GIT_SYNC_KNOWN_HOSTS", "GIT_KNOWN_HOSTS"),
|
||||||
"enable SSH known_hosts verification")
|
"enable SSH known_hosts verification")
|
||||||
|
|
@ -697,7 +714,7 @@ func main() {
|
||||||
if *flCookieFile {
|
if *flCookieFile {
|
||||||
handleConfigError(log, true, "ERROR: only one of --ssh and --cookie-file may be specified")
|
handleConfigError(log, true, "ERROR: only one of --ssh and --cookie-file may be specified")
|
||||||
}
|
}
|
||||||
if *flSSHKeyFile == "" {
|
if len(*flSSHKeyFiles) == 0 {
|
||||||
handleConfigError(log, true, "ERROR: --ssh-key-file must be specified when --ssh is set")
|
handleConfigError(log, true, "ERROR: --ssh-key-file must be specified when --ssh is set")
|
||||||
}
|
}
|
||||||
if *flSSHKnownHosts {
|
if *flSSHKnownHosts {
|
||||||
|
|
@ -821,8 +838,8 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flSSH {
|
if *flSSH {
|
||||||
if err := git.SetupGitSSH(*flSSHKnownHosts, *flSSHKeyFile, *flSSHKnownHostsFile); err != nil {
|
if err := git.SetupGitSSH(*flSSHKnownHosts, *flSSHKeyFiles, *flSSHKnownHostsFile); err != nil {
|
||||||
log.Error(err, "can't set up git SSH", "keyFile", *flSSHKeyFile, "knownHosts", *flSSHKnownHosts, "knownHostsFile", *flSSHKnownHostsFile)
|
log.Error(err, "can't set up git SSH", "keyFile", *flSSHKeyFiles, "knownHosts", *flSSHKnownHosts, "knownHostsFile", *flSSHKnownHostsFile)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1928,7 +1945,7 @@ func (git *repoSync) StoreCredentials(ctx context.Context, username, password st
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (git *repoSync) SetupGitSSH(setupKnownHosts bool, pathToSSHSecret, pathToSSHKnownHosts string) error {
|
func (git *repoSync) SetupGitSSH(setupKnownHosts bool, pathsToSSHSecrets []string, pathToSSHKnownHosts string) error {
|
||||||
git.log.V(1).Info("setting up git SSH credentials")
|
git.log.V(1).Info("setting up git SSH credentials")
|
||||||
|
|
||||||
// If the user sets GIT_SSH_COMMAND we try to respect it.
|
// If the user sets GIT_SSH_COMMAND we try to respect it.
|
||||||
|
|
@ -1937,10 +1954,12 @@ func (git *repoSync) SetupGitSSH(setupKnownHosts bool, pathToSSHSecret, pathToSS
|
||||||
sshCmd = "ssh"
|
sshCmd = "ssh"
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(pathToSSHSecret); err != nil {
|
for _, p := range pathsToSSHSecrets {
|
||||||
return fmt.Errorf("can't access SSH key file %s: %w", pathToSSHSecret, err)
|
if _, err := os.Stat(p); err != nil {
|
||||||
|
return fmt.Errorf("can't access SSH key file %s: %w", p, err)
|
||||||
|
}
|
||||||
|
sshCmd += fmt.Sprintf(" -i %s", p)
|
||||||
}
|
}
|
||||||
sshCmd += fmt.Sprintf(" -i %s", pathToSSHSecret)
|
|
||||||
|
|
||||||
if setupKnownHosts {
|
if setupKnownHosts {
|
||||||
if _, err := os.Stat(pathToSSHKnownHosts); err != nil {
|
if _, err := os.Stat(pathToSSHKnownHosts); err != nil {
|
||||||
|
|
@ -2463,8 +2482,10 @@ OPTIONS
|
||||||
Use SSH for git authentication and operations.
|
Use SSH for git authentication and operations.
|
||||||
|
|
||||||
--ssh-key-file <string>, $GITSYNC_SSH_KEY_FILE
|
--ssh-key-file <string>, $GITSYNC_SSH_KEY_FILE
|
||||||
The SSH key to use when using --ssh. If not specified, this
|
The SSH key(s) to use when using --ssh. This flag may be specified
|
||||||
defaults to "/etc/git-secret/ssh".
|
more than once and the environment variable will be parsed like
|
||||||
|
PATH - using a colon (':') to separate elements. If not specified,
|
||||||
|
this defaults to "/etc/git-secret/ssh".
|
||||||
|
|
||||||
--ssh-known-hosts, $GITSYNC_SSH_KNOWN_HOSTS
|
--ssh-known-hosts, $GITSYNC_SSH_KNOWN_HOSTS
|
||||||
Enable SSH known_hosts verification when using --ssh. If not
|
Enable SSH known_hosts verification when using --ssh. If not
|
||||||
|
|
|
||||||
49
test_e2e.sh
49
test_e2e.sh
|
|
@ -238,9 +238,12 @@ function wait_for_sync() {
|
||||||
|
|
||||||
# Init SSH for test cases.
|
# Init SSH for test cases.
|
||||||
DOT_SSH="$DIR/dot_ssh"
|
DOT_SSH="$DIR/dot_ssh"
|
||||||
mkdir -p "$DOT_SSH"
|
for i in $(seq 1 3); do
|
||||||
ssh-keygen -f "$DOT_SSH/id_test" -P "" >/dev/null
|
mkdir -p "$DOT_SSH/$i"
|
||||||
cat "$DOT_SSH/id_test.pub" > "$DOT_SSH/authorized_keys"
|
ssh-keygen -f "$DOT_SSH/$i/id_test" -P "" >/dev/null
|
||||||
|
mkdir -p "$DOT_SSH/server/$i"
|
||||||
|
cat "$DOT_SSH/$i/id_test.pub" > "$DOT_SSH/server/$i/authorized_keys"
|
||||||
|
done
|
||||||
chmod -R g+r "$DOT_SSH"
|
chmod -R g+r "$DOT_SSH"
|
||||||
|
|
||||||
TEST_TOOLS="_test_tools"
|
TEST_TOOLS="_test_tools"
|
||||||
|
|
@ -279,7 +282,9 @@ function GIT_SYNC() {
|
||||||
-v "$(pwd)/$TEST_TOOLS":"/$TEST_TOOLS":ro \
|
-v "$(pwd)/$TEST_TOOLS":"/$TEST_TOOLS":ro \
|
||||||
--env "$EXECHOOK_ENVKEY=$EXECHOOK_ENVVAL" \
|
--env "$EXECHOOK_ENVKEY=$EXECHOOK_ENVVAL" \
|
||||||
-v "$RUNLOG":/var/log/runs \
|
-v "$RUNLOG":/var/log/runs \
|
||||||
-v "$DOT_SSH/id_test":"/etc/git-secret/ssh":ro \
|
-v "$DOT_SSH/1/id_test":"/ssh/secret.1":ro \
|
||||||
|
-v "$DOT_SSH/2/id_test":"/ssh/secret.2":ro \
|
||||||
|
-v "$DOT_SSH/3/id_test":"/ssh/secret.3":ro \
|
||||||
"${IMAGE}" \
|
"${IMAGE}" \
|
||||||
-v=6 \
|
-v=6 \
|
||||||
--add-user \
|
--add-user \
|
||||||
|
|
@ -2689,15 +2694,44 @@ function e2e::submodule_sync_relative() {
|
||||||
rm -rf $SUBMODULE
|
rm -rf $SUBMODULE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Test SSH with bad key
|
||||||
|
##############################################
|
||||||
|
function e2e::auth_ssh_wrong_key() {
|
||||||
|
echo "$FUNCNAME" > "$REPO/file"
|
||||||
|
|
||||||
|
# Run a git-over-SSH server. Use key #1.
|
||||||
|
CTR=$(docker_run \
|
||||||
|
-v "$DOT_SSH/server/3":/dot_ssh:ro \
|
||||||
|
-v "$REPO":/src:ro \
|
||||||
|
e2e/test/sshd)
|
||||||
|
IP=$(docker_ip "$CTR")
|
||||||
|
git -C "$REPO" commit -qam "$FUNCNAME"
|
||||||
|
|
||||||
|
# Try to sync with key #2.
|
||||||
|
GIT_SYNC \
|
||||||
|
--one-time \
|
||||||
|
--repo="test@$IP:/src" \
|
||||||
|
--root="$ROOT" \
|
||||||
|
--link="link" \
|
||||||
|
--ssh \
|
||||||
|
--ssh-key-file="/ssh/secret.2" \
|
||||||
|
--ssh-known-hosts=false \
|
||||||
|
|| true
|
||||||
|
|
||||||
|
# check for failure
|
||||||
|
assert_file_absent "$ROOT/link/file"
|
||||||
|
}
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
# Test SSH
|
# Test SSH
|
||||||
##############################################
|
##############################################
|
||||||
function e2e::auth_ssh() {
|
function e2e::auth_ssh() {
|
||||||
echo "$FUNCNAME" > "$REPO/file"
|
echo "$FUNCNAME" > "$REPO/file"
|
||||||
|
|
||||||
# Run a git-over-SSH server
|
# Run a git-over-SSH server. Use key #3 to exercise the multi-key logic.
|
||||||
CTR=$(docker_run \
|
CTR=$(docker_run \
|
||||||
-v "$DOT_SSH":/dot_ssh:ro \
|
-v "$DOT_SSH/server/3":/dot_ssh:ro \
|
||||||
-v "$REPO":/src:ro \
|
-v "$REPO":/src:ro \
|
||||||
e2e/test/sshd)
|
e2e/test/sshd)
|
||||||
IP=$(docker_ip "$CTR")
|
IP=$(docker_ip "$CTR")
|
||||||
|
|
@ -2713,6 +2747,9 @@ function e2e::auth_ssh() {
|
||||||
--root="$ROOT" \
|
--root="$ROOT" \
|
||||||
--link="link" \
|
--link="link" \
|
||||||
--ssh \
|
--ssh \
|
||||||
|
--ssh-key-file="/ssh/secret.1" \
|
||||||
|
--ssh-key-file="/ssh/secret.2" \
|
||||||
|
--ssh-key-file="/ssh/secret.3" \
|
||||||
--ssh-known-hosts=false \
|
--ssh-known-hosts=false \
|
||||||
&
|
&
|
||||||
wait_for_sync "${MAXWAIT}"
|
wait_for_sync "${MAXWAIT}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue